home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / inventor / sharedSV / SoSceneViewer.c++ < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  118.5 KB  |  4,133 lines

  1. /*
  2.  * Copyright (c) 1991, 1992 Silicon Graphics, Inc.
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and
  5.  * its documentation for any purpose is hereby granted without fee, provided
  6.  * that the name of Silicon Graphics may not be used in any advertising or
  7.  * publicity relating to the software without the specific, prior written
  8.  * permission of Silicon Graphics.
  9.  *
  10.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
  11.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
  12.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
  13.  *
  14.  * IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
  15.  * INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
  16.  * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
  17.  * POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
  18.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  19.  */
  20.  
  21. /*
  22.  * Copyright (C) 1990,91,92   Silicon Graphics, Inc.
  23.  *
  24.  * 
  25.  _______________________________________________________________________
  26.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  27.  |
  28.  |   $Revision: 1.1010 $
  29.  |
  30.  |   Classes    : SoSceneViewer
  31.  |
  32.  |   Author(s)    : Thad Beier, David Mott, Alain Dumesny, Paul Isaacs,
  33.  |          Rikk Carey, Dave Immel
  34.  |
  35.  ______________  S I L I C O N   G R A P H I C S   I N C .  ____________
  36.  _______________________________________________________________________
  37.  */
  38.  
  39. #include "Common.h"
  40. #include <stdlib.h>
  41. #include <getopt.h>
  42. #include <string.h>
  43. #include <stdio.h>
  44. #include <time.h>
  45. #include <unistd.h>
  46. #include <sys/types.h>
  47. #include <sys/socket.h>
  48. #include <netinet/in.h>
  49. #include <net/if.h>
  50. #include <net/soioctl.h>
  51. #include <arpa/inet.h>
  52. #include "multicast.h"
  53. #include <unistd.h> // for access()
  54. #include <sys/types.h>
  55. #include <sys/stat.h>
  56.  
  57. #include <X11/StringDefs.h>
  58. #include <X11/Intrinsic.h>
  59. #include <X11/Xatom.h>
  60.  
  61. #include <Xm/Xm.h>
  62. #include <Xm/BulletinB.h>
  63. #include <Xm/CascadeB.h>
  64. #include <Xm/CascadeBG.h>
  65. #include <Xm/FileSB.h>
  66. #include <Xm/Form.h>
  67. #include <Xm/Label.h>
  68. #include <Xm/FileSB.h>
  69. #include <Xm/PushB.h>
  70. #include <Xm/PushBG.h>
  71. #include <Xm/SeparatoG.h>
  72. #include <Xm/Text.h>
  73. #include <Xm/ToggleB.h>
  74. #include <Xm/ToggleBG.h>
  75.  
  76. #include <Inventor/So.h>
  77. #include <Inventor/SoBaseKit.h>
  78. #include <Inventor/SoXt.h>
  79. #include <Inventor/SoXtColorEditor.h>
  80. #include <Inventor/SoBoxHighlight.h>
  81. #include <Inventor/SoLineHighlight.h>
  82. #include <Inventor/SoXtClipboard.h>
  83. #include <Inventor/SoXtDirectionalLightEditor.h>
  84. #include <Inventor/SoXtFileBrowser.h>
  85. #include <Inventor/SoXtMaterialEditor.h>
  86. #include <Inventor/SoXtPrintDialog.h>
  87. #include <Inventor/SoSelection.h>
  88. #include <Inventor/SoXtTransformSliderSet.h>
  89. #include <Inventor/SoXtResource.h>
  90. #include <Inventor/SoSensor.h>
  91. #include <Inventor/actions/SoGetBoundingBoxAction.h>
  92. #include <Inventor/actions/SoGetMatrixAction.h>
  93. #include <Inventor/nodes/SoSwitch.h>
  94. #include <Inventor/nodes/SoLight.h>
  95. #include <Inventor/nodes/SoDirectionalLight.h>
  96. #include <Inventor/nodes/SoPointLight.h>
  97. #include <Inventor/nodes/SoSpotLight.h>
  98. #include <Inventor/manips/SoDragPointManip.h>
  99. #include <Inventor/manips/SoHandleBoxManip.h>
  100. #include <Inventor/manips/SoJackManip.h>
  101. #include <Inventor/manips/SoTrackballManip.h>
  102. #include <Inventor/manips/SoTransformBoxManip.h>
  103. #include <Inventor/manips/SoDirectionalLightManip.h>
  104. #include <Inventor/manips/SoPointLightManip.h>
  105. #include <Inventor/manips/SoSpotLightManip.h>
  106. #include <Inventor/viewers/SoXtExaminerViewer.h>
  107. #include <Inventor/viewers/SoXtWalkViewer.h>
  108. #include <Inventor/viewers/SoXtFlyViewer.h>
  109. #include <Inventor/viewers/SoXtPlaneViewer.h>
  110. #include <Inventor/viewers/SoXtViewer.h>
  111.  
  112. #include "SoSceneViewer.h"
  113. #include "SoSceneMenu.h"
  114. #include "SvManipList.h"
  115.  
  116. #include <gl/gl.h>
  117. #include <malloc.h>
  118. #ifdef DEBUG
  119. #include <assert.h>
  120. #endif
  121.  
  122. //
  123. //  Macros and constants
  124. //
  125.  
  126. // toggle button macros
  127. #define TOGGLE_ON(BUTTON) \
  128.     XmToggleButtonSetState((Widget) BUTTON, TRUE, FALSE)
  129. #define TOGGLE_OFF(BUTTON) \
  130.     XmToggleButtonSetState((Widget) BUTTON, FALSE, FALSE)
  131.  
  132. #define    FOG_FUDGE    1.6
  133. #define SV_NUM_LIGHTS    6
  134.  
  135. #define SWITCH_LIGHT_OFF(SWITCH) (SWITCH)->whichChild.setValue(SO_SWITCH_NONE)
  136. #define SWITCH_LIGHT_ON(SWITCH)  (SWITCH)->whichChild.setValue(SO_SWITCH_ALL)
  137. #define IS_LIGHT_ON(SWITCH)     ((SWITCH)->whichChild.getValue() == SO_SWITCH_ALL)
  138.  
  139. #define SV_ENV_LABEL "SoSceneViewer Environment v3.0"
  140.  
  141. //
  142. //  Structs
  143. //
  144.  
  145. struct SoSceneViewerData {
  146.     int id;
  147.     SoSceneViewer *classPt;
  148.     Widget widget;
  149. };
  150.  
  151. struct SvLightData {
  152.     SoSceneViewer   *classPt;
  153.     SoSwitch        *lightSwitch;
  154.     SoLight        *light;
  155.     SoLight::Type   type;
  156.     char        *name;
  157.     SoXtColorEditor *colorEditor;
  158.     SoDragManip        *manip;
  159.     Widget        cascadeWidget;
  160.     Widget        submenuWidget;
  161.     Widget        onOffWidget;
  162.     Widget        iconWidget;
  163.     Widget        editColorWidget;
  164.     Widget        removeWidget;
  165. };
  166.  
  167. // added by smf
  168. extern SoSceneViewer *mysv;
  169. extern SoDataSensor *envirosensor;
  170. extern SoTimerSensor *timersensor;
  171. extern void printScreen(SoSceneViewer *);
  172. void mystartcallback(void *,SoXtViewer *);
  173. void mystopcallback(void *,SoXtViewer *);
  174. int flag;
  175. int timerflag=1;
  176. int rotflag;
  177. struct stat buf;
  178. time_t lasttime=-1;
  179. char mybuff[1000];
  180. char temp[1000];
  181. extern    struct sockaddr_in  inaddr,outaddr;
  182. extern    int                 inaddrlen,outaddrlen, infd, outfd, cnt, i;
  183. extern    struct ip_mreq      mreq;
  184. extern    char                *group ;
  185. extern    u_short             port ;
  186. extern    u_char              ttl ;
  187. extern    int                 send_mode ;
  188. extern    int                 iflag ;
  189. extern    char                *interface;
  190. extern    struct in_addr      ifaddr;
  191. extern    struct in_addr      grpaddr;
  192.  
  193.  
  194.  
  195. ////////////////////////////////////////////////////////////////////////
  196. //
  197. // Description:
  198. //    Constructor for the SoSceneViewer.
  199. //      Creates the Topbar menu
  200. //
  201. // Use: public
  202.  
  203. SoSceneViewer::SoSceneViewer(SoSelection *inputGraph, const char *envFile)
  204. //
  205. ////////////////////////////////////////////////////////////////////////
  206. {
  207.     Arg        args[1];
  208.     int        i;
  209.     
  210.     SoXtComponent::setSize( SbVec2s(520, 480) );
  211.  
  212.     // selection is the users scene graph.
  213.     selection  = inputGraph;
  214.     createLightsCameraEnvironment();
  215.     
  216.     // the scene viewer supplies its own camera and lights.
  217.     // in fact, we remove any cameras that might be in the users graph.
  218.     sceneGraph = new SoSeparator();
  219.     sceneGraph->ref();    // must ref it
  220.     sceneGraph->addChild(lightsCameraEnvironment);
  221.     sceneGraph->addChild(selection);
  222. #ifndef EXPLORER
  223.     removeCameras(selection);
  224. #endif
  225.     
  226.     //
  227.     // Widget and menu variables
  228.     //
  229.     mgrWidget = NULL;
  230.     showMenuFlag = TRUE;
  231.     menuWidget = NULL;
  232.     menuItems = new SoSceneViewerData[SV_MENU_NUM];
  233.     for (i=0; i<SV_MENU_NUM; i++) {
  234.     menuItems[i].id = i;
  235.     menuItems[i].classPt = this;
  236.     menuItems[i].widget = NULL;
  237.     }
  238.     
  239.     //
  240.     // File
  241.     //
  242.     fileName     = NULL;
  243.     fileDialog     = NULL;
  244.     browser      = NULL;
  245.     printDialog     = NULL;
  246.     // check which file browser to use
  247.     char *browserName = getenv("SO_FILE_BROWSER");
  248.     if (browserName != NULL && strcasecmp(browserName, "showcase") == 0)
  249.     useShowcaseBrowser = TRUE;
  250.     else
  251.     useShowcaseBrowser = FALSE;
  252.     
  253.     //
  254.     // Edit
  255.     //
  256.     highlightColorEditor = NULL;
  257.  
  258.     //
  259.     // Viewing
  260.     //
  261.     // Allocate only one viewer at a time. The other viewers will
  262.     // be allocated as needed to increase speed and save memory.
  263.     //
  264.     for (i=0; i<4; i++)
  265.     viewerList[i] = NULL;
  266.     whichViewer = SV_VWR_EXAMINER;
  267.     setTitle("SharedSV (Examiner) author: fine@detroit.sgi.com");
  268.     currentViewer = viewerList[whichViewer] = new SoXtExaminerViewer;
  269.     currentViewer->setSceneGraph(sceneGraph);
  270. // added by smf
  271.     currentViewer->addStartCallback(mystartcallback,currentViewer);
  272.     currentViewer->addFinishCallback(mystopcallback,currentViewer);
  273.     // since we created the camera, do a view all and save this
  274.     // as the starting point (don't want default camera values).
  275.     viewAll();
  276.     saveHomePosition();
  277.     
  278.     // fog
  279.     fogFlag = FALSE;
  280.     environment->fogType.setValue( SoEnvironment::NONE );
  281.     environment->fogColor.setValue( getBackgroundColor() );
  282.  
  283.     antialiasingFlag = FALSE;
  284.     backgroundColorEditor = NULL;
  285.  
  286.     //
  287.     // Selection
  288.     //     These callbacks are used to update the SceneViewer state after
  289.     //     the current selection changes (e.g. attach/detach editors and manips).
  290.     //
  291.     selection->addObjectSelectedCallback( SoSceneViewer::selectionCallback, this );
  292.     selection->addObjectDeselectedCallback( SoSceneViewer::deselectionCallback, this );
  293.     lineHighlight = new SoLineHighlight;
  294.     boxHighlight = new SoBoxHighlight;
  295.     
  296.     // default selection highlight style
  297.     selection->setHighlightStyle(boxHighlight);
  298.     
  299.     //
  300.     // Editors
  301.     //
  302.     ignoreCallback = FALSE;
  303.     materialEditor  = NULL;
  304.     colorEditor        = NULL;
  305.     transformSliderSet = NULL;
  306.  
  307.     //
  308.     // Manips
  309.     //
  310.     curManip = SV_NONE;
  311.     curManipReplaces = TRUE;
  312.     maniplist = new SvManipList;
  313.     
  314. #ifdef EXPLORER
  315.     //
  316.     // User callback
  317.     //
  318.     userModeCB = NULL;
  319.     userModedata = NULL;
  320.     userModeFlag = FALSE;
  321. #endif /* EXPLORER */
  322.     
  323.     //
  324.     // Lights
  325.     //
  326.     ambientColorEditor = NULL;
  327.     headlightData = new SvLightData;
  328.     headlightData->classPt = this;
  329.     headlightData->name = strdup("Headlight");
  330.     headlightData->type = SoLight::DIRECTIONAL;
  331.     headlightData->colorEditor = NULL;
  332.     headlightData->manip = NULL;
  333.     headlightEditor = NULL;
  334.     calculatedLightManipSize = FALSE;
  335.     
  336.     // do this after everything else has been set up
  337.     if (envFile != NULL)
  338.         readEnvFile(envFile);
  339. }
  340.  
  341. ////////////////////////////////////////////////////////////////////////
  342. //
  343. // Description:
  344. //    Destructor.
  345. //
  346. // Use: public
  347.  
  348. SoSceneViewer::~SoSceneViewer()
  349. //
  350. ////////////////////////////////////////////////////////////////////////
  351. {
  352.     // detach and delete the viewers
  353.     currentViewer->setSceneGraph(NULL);
  354.     delete (SoXtExaminerViewer *) viewerList[SV_VWR_EXAMINER];
  355.     delete (SoXtFlyViewer *) viewerList[SV_VWR_FLY];
  356.     delete (SoXtWalkViewer *) viewerList[SV_VWR_WALK];
  357.     delete (SoXtPlaneViewer *) viewerList[SV_VWR_PLANE];
  358.     
  359.     // delete menu items data
  360.     delete [ /*SV_MENU_NUM*/ ] menuItems;
  361.     delete headlightData;
  362.     delete headlightEditor;
  363.     
  364.     delete browser;
  365.     delete printDialog;
  366.     
  367.     // Editor components
  368.     delete materialEditor;
  369.     delete colorEditor;
  370.     delete transformSliderSet;
  371.     delete ambientColorEditor;
  372.     delete backgroundColorEditor;
  373.  
  374.     // detach and delete the manips
  375.     detachManipFromAll();
  376.     delete maniplist;
  377.  
  378.     sceneGraph->unref();
  379. }
  380.  
  381. ////////////////////////////////////////////////////////////////////////
  382. //
  383. // Description:
  384. //    New data is going to be coming into the viewer.  Time to disconnect all
  385. //  manipulators and picking, and wait for new information.  Might as well go
  386. //  into a viewing mode as well, this gets rid of the manipulators, and puts
  387. //  the user in control of viewing when new data shows up.
  388. //
  389. // Use: public
  390. void
  391. SoSceneViewer::newData()
  392. //
  393. ////////////////////////////////////////////////////////////////////////
  394. {
  395.     selection->deselectAll();
  396. }
  397.  
  398. #ifdef EXPLORER
  399. ////////////////////////////////////////////////////////////////////////
  400. //
  401. // Description:
  402. //    This sets the user mode callack routine
  403. //
  404. // Use: public
  405. void 
  406. SoSceneViewer::setUserModeEventCallback(SoXtRenderAreaEventCB *fcn)
  407. //
  408. ////////////////////////////////////////////////////////////////////////
  409. {
  410.     userModeCB = fcn;
  411.     userModedata = currentViewer->getSceneGraph();
  412.     if (userModeFlag)
  413.     currentViewer->setEventCallback(userModeCB, userModedata);
  414. }
  415. #endif /* EXPLORER */
  416.  
  417. ////////////////////////////////////////////////////////////////////////
  418. //
  419. // Description:
  420. //    switches from the current viewer to the given viewer. The new
  421. //  viewer will automatically be allocated if needed, and set to have 
  422. //  the same settings the current viewer has (drawing style, buffer 
  423. //  type, etc..).
  424. //
  425. // Use: private
  426. void
  427. SoSceneViewer::switchToViewer(SvEViewer newViewer)
  428. //
  429. ////////////////////////////////////////////////////////////////////////
  430. {
  431.     if (whichViewer == newViewer)
  432.         return;
  433.     
  434.     // allocate the viewer if needed and set the window title.
  435.     switch (newViewer) {
  436.     case SV_VWR_EXAMINER:
  437.         if ( viewerList[newViewer] == NULL )
  438.         viewerList[newViewer] = new SoXtExaminerViewer;
  439.         setTitle("SharedSV (Examiner) author: fine@detroit.sgi.com");
  440.         break;
  441.     case SV_VWR_FLY:
  442.         if ( viewerList[newViewer] == NULL )
  443.         viewerList[newViewer] = new SoXtFlyViewer;
  444.         setTitle("SharedSV (Fly) author: fine@detroit.sgi.com");
  445.         break;
  446.     case SV_VWR_WALK:
  447.         if ( viewerList[newViewer] == NULL )
  448.         viewerList[newViewer] = new SoXtWalkViewer;
  449.         setTitle("SharedSV (Walk) author: fine@detroit.sgi.com");
  450.         break;
  451.     case SV_VWR_PLANE:
  452.         if ( viewerList[newViewer] == NULL )
  453.         viewerList[newViewer] = new SoXtPlaneViewer;
  454.         setTitle("SharedSV (Plane) author: fine@detroit.sgi.com");
  455.         break;
  456.     }
  457.     SoXtFullViewer *newVwr = viewerList[newViewer];
  458.     
  459.     //
  460.     // make sure the new viewer has all the same settings as 
  461.     // the current viewer. 
  462.     //
  463.     // XtRenderArea methods
  464.     newVwr->setBackgroundColor( currentViewer->getBackgroundColor() );
  465.     newVwr->setTransparencyType( currentViewer->getTransparencyType() );
  466.     SbBool smooth; int num;
  467.     currentViewer->getAntialiasing(smooth, num);
  468.     newVwr->setAntialiasing(smooth, num);
  469.     newVwr->setClearBeforeRender( currentViewer->isClearBeforeRender() );
  470.     newVwr->setAutoRedraw( currentViewer->isAutoRedraw() );
  471.     // XtViewer methods
  472.     newVwr->setHeadlight( currentViewer->isHeadlight() );
  473.     newVwr->setDrawStyle( currentViewer->getDrawStyle() );
  474.     newVwr->setBufferingType( currentViewer->getBufferingType() );
  475.     newVwr->setViewing( currentViewer->isViewing() );
  476.     newVwr->setAutoClipping( currentViewer->isAutoClipping() );
  477.     newVwr->setGLRenderCaching( currentViewer->isGLRenderCaching() );
  478.     newVwr->setSeekTime( currentViewer->getSeekTime() );
  479.     // XtFullViewer methods
  480.     newVwr->setDecoration( currentViewer->isDecoration() );
  481.     
  482. #ifdef EXPLORER
  483.     if (userModeFlag)
  484.     newVwr->setEventCallback(userModeCB, userModedata);
  485.     else
  486.     newVwr->setEventCallback(NULL, NULL);
  487. #endif
  488.     
  489.     // build and layout the new viewer
  490.     buildAndLayoutViewer(newVwr);
  491.     
  492.     // finally switch to the new viewer by attaching/showing the new
  493.     // viewer, and detaching/hidding the old viewer (hide is done 
  494.     // last to reduce flicker).
  495.     currentViewer->setSceneGraph(NULL);
  496.     newVwr->setSceneGraph(sceneGraph);
  497.     newVwr->show();
  498.     currentViewer->hide();
  499.     whichViewer = newViewer;
  500.     currentViewer = newVwr;
  501. }
  502.  
  503. ////////////////////////////////////////////////////////////////////////
  504. //
  505. // Description:
  506. //    Move up the picked path to the parent group.
  507. //
  508. // Use: public
  509.  
  510. void
  511. SoSceneViewer::pickParent()
  512. //
  513. ////////////////////////////////////////////////////////////////////////
  514. {
  515.     SoPath      *pickPath;
  516.     int            newIndex;
  517.  
  518.     pickPath = (*selection)[selection->getNumSelected() - 1];    // last guy or gal
  519.     if(pickPath == NULL || pickPath->getLength() == 1)
  520.     return;
  521.  
  522.     SoTypeList    *priorities = selection->getSelectTypePriorityList();
  523.     SoType    checkType;
  524.     int        priority;
  525.     SbBool    gotOne;
  526.  
  527.     for ( priority = 0, gotOne = FALSE;
  528.      gotOne == FALSE && priority < priorities->length();
  529.      priority++ ) {
  530.  
  531.     checkType = (*priorities)[priority];
  532.     if (checkType == SoNode::getClassTypeId()) { 
  533.         newIndex = pickPath->getLength() - 2; // parent of tail
  534.         gotOne = TRUE;    
  535.     }
  536.     else {
  537.         for(newIndex = pickPath->getLength() - 2; newIndex >= 0; newIndex--) {
  538.         if(pickPath->getNode(newIndex)->isOfType(checkType)) {
  539.             gotOne = TRUE;
  540.             break;
  541.         }
  542.         }
  543.     }
  544.     }
  545.     if ( gotOne == FALSE )
  546.     return;
  547.  
  548.     // cannot select the selection node (make sure we're not)
  549.  
  550.     if (pickPath->getNode(newIndex) == selection) {
  551.         fprintf(stderr, "No more parents to pick (cannot pick above the selection node)\n");
  552.         return;
  553.     }
  554.     
  555.     pickPath->ref();                // need to ref it, because
  556.                         // selection->clear unref's it
  557.     selection->deselectAll();
  558.     pickPath->truncate(newIndex + 1);        // Make path end at newIndex
  559.     selection->select(pickPath);        // add path back in
  560.     pickPath->unref();                // now we can unref it, again
  561. }
  562.  
  563. ////////////////////////////////////////////////////////////////////////
  564. //
  565. // Description:
  566. //    Pick all group nodes and shapes under selection.
  567. //
  568. // Use: private
  569. void
  570. SoSceneViewer::pickAll()
  571. //
  572. ////////////////////////////////////////////////////////////////////////
  573. {
  574.     selection->deselectAll();
  575.  
  576. #ifdef DEBUG
  577.     assert(selection != NULL);
  578. #endif
  579.  
  580.     SoPathList myPaths;
  581.  
  582.     // Our callbacks on the selection's 'select' method may add 
  583.     // more children to the selection node (by making a trackball or handlebox)
  584.     // Therefore, we must first determine the selections by storing
  585.     // paths to them.
  586.     // Following this, we call 'select' on each path, in turn.
  587.  
  588.     //
  589.     // Create paths from the selection node to all of it's children
  590.     // that are groups or shapes.
  591.     //
  592.     for (int i = 0; i < selection->getNumChildren(); i++) {
  593.         SoNode *node = selection->getChild(i);
  594.     if ((node->isOfType(SoGroup::getClassTypeId()) ||
  595.          node->isOfType(SoShape::getClassTypeId())) &&
  596.         (! node->isOfType(SoManipulator::getClassTypeId())))
  597.  
  598.     {
  599.         SoPath *thisPath = new SoPath(selection);
  600.         thisPath->append(i);
  601.  
  602.         myPaths.append( thisPath );
  603.     }
  604.     }
  605.  
  606.     //
  607.     // Select each path in 'myPaths'
  608.     //
  609.     for (int j = 0; j < myPaths.length(); j++)
  610.     selection->select(myPaths[j]);
  611. }
  612.  
  613.  
  614. ////////////////////////////////////////////////////////////////////////
  615. //
  616. // Description:
  617. //    This routine first detaches manipulators from all selected objects,
  618. //      then attaches a manipulator to all selected objects.
  619. //
  620. // Use: private
  621.  
  622. void
  623. SoSceneViewer::replaceAllManips( 
  624.     SvEManipMode manipMode )        // Current manipulator
  625. //
  626. ////////////////////////////////////////////////////////////////////////
  627. {
  628.     detachManipFromAll();
  629.     attachManipToAll( manipMode );
  630. }
  631.  
  632. ////////////////////////////////////////////////////////////////////////
  633. //
  634. // Description:
  635. //    This routine attaches a manipulator to all selected objects.
  636. //
  637. // Use: private
  638.  
  639. void
  640. SoSceneViewer::attachManipToAll( 
  641.     SvEManipMode manipMode )        // Current manipulator
  642. //
  643. ////////////////////////////////////////////////////////////////////////
  644. {
  645.     int        i;
  646.  
  647.     for ( i = 0; i < selection->getNumSelected(); i++ ) {
  648.     SoPath *p = (*selection)[i];
  649.     attachManip( manipMode, p );
  650.     }
  651. }
  652.  
  653. ////////////////////////////////////////////////////////////////////////
  654. //
  655. // Description:
  656. //    This routine attaches and activates a manipulator.  
  657. //
  658. // Use: private
  659.  
  660. void
  661. SoSceneViewer::attachManip( 
  662.     SvEManipMode manipMode,        // Current manipulator
  663.     SoPath *selectedObject )        // Which selection to attach to
  664. //
  665. ////////////////////////////////////////////////////////////////////////
  666. {
  667.     SoManipulator     *theManip;
  668.     SoPath        *xfPath;
  669.  
  670.     //
  671.     // Attach to a manipulator.
  672.     //
  673.  
  674.     if ( manipMode == SV_NONE )
  675.     return;
  676.  
  677.     xfPath = findTransformForAttach( selectedObject );
  678.     xfPath->ref();
  679.     theManip = NULL;
  680.  
  681.     switch( manipMode ) {
  682.       case SV_TRACKBALL:
  683.     theManip = new SoTrackballManip;
  684.     break;
  685.  
  686.       case SV_HANDLEBOX:
  687.     theManip = new SoHandleBoxManip;
  688.       break;
  689.  
  690.       case SV_JACK:
  691.     theManip = new SoJackManip;
  692.       break;
  693.  
  694.       case SV_XFBOX:
  695.     theManip = new SoTransformBoxManip;
  696.       break;
  697.  
  698.       case SV_DRAGPOINT:
  699.     theManip = new SoDragPointManip;
  700.       break;
  701.  
  702.       case SV_NONE:
  703.     return;
  704.     }
  705.  
  706.     if ( theManip ) {
  707.  
  708.     theManip->ref();
  709.  
  710.     if ( !theManip->attach( xfPath ) ) {
  711.         theManip->unref();
  712. #ifdef DEBUG
  713.         fprintf(stderr,"DBG> Fatal Error: in SoSceneViewer::attachManip\n");
  714.         fprintf(stderr,"   > manip->attach() failed!\n" );
  715. #endif
  716.     }
  717.  
  718.     //
  719.     // Add the manipulator below the selection node. 
  720.     // We keep manipulators off to the side so that they will
  721.     // be ignored during highlighting. Since each manipulator
  722.     // has a reset transform and a sensor on its target, this
  723.     // is not a problem.
  724.     //
  725.     selection->addChild( theManip );
  726.  
  727.     // Add manip and path to the maniplist (maniplist will ref/unref)
  728.     maniplist->append(selectedObject, theManip);
  729.  
  730.     theManip->unref();
  731.  
  732.     // Special case! If the manip is a jack manip, then replace
  733.     // the dragPointDragger part with a path to the object itself!
  734.     if ( manipMode == SV_JACK )
  735.         theManip->replacePart("dragPointDragger", selectedObject );
  736.     }
  737.  
  738.     xfPath->unref();
  739. }
  740.  
  741.  
  742. ////////////////////////////////////////////////////////////////////////
  743. //
  744. // Description:
  745. //    This routine detaches the manipulators from all selected objects.
  746. //
  747. // Use: private
  748. void
  749. SoSceneViewer::detachManipFromAll() 
  750. //
  751. ////////////////////////////////////////////////////////////////////////
  752. {
  753.     //
  754.     // Loop from the end of the list to the start.
  755.     //
  756.     for (int i = selection->getNumSelected() - 1; i >= 0 ; i-- ) {
  757.     SoPath *p = (SoPath *) (*selection)[i];
  758.     detachManip( p );
  759.     }
  760. }
  761.  
  762.  
  763. ////////////////////////////////////////////////////////////////////////
  764. //
  765. // Description:
  766. //    This routine detaches a manipulator.  
  767. //
  768. // Use: private
  769.  
  770. void
  771. SoSceneViewer::detachManip(
  772.     SoPath *p )        // Selection object that is being removed
  773. //
  774. ////////////////////////////////////////////////////////////////////////
  775. {
  776.     //
  777.     // Detach manip and remove from scene graph.
  778.     //
  779.     int which = maniplist->find(p);
  780.     // See if this path is registered in the manip list.
  781.     if (which != -1) {
  782.     // remove from scene graph
  783.     SoManipulator *manip = maniplist->getManip(which);
  784.     manip->detach();
  785.     selection->removeChild(manip);
  786.     
  787.     // remove from maniplist
  788.     maniplist->remove(which);
  789.     }
  790. }
  791.  
  792. ////////////////////////////////////////////////////////////////////////
  793. //
  794. // Description:
  795. //    See the selection from the camera
  796. //
  797. // Use: public
  798. void
  799. SoSceneViewer::viewSelection()
  800. //
  801. ////////////////////////////////////////////////////////////////////////
  802. {
  803.     if (selection->getNumSelected() == 0) {
  804.     viewAll();
  805.     return;
  806.     }
  807.     
  808.     SoPath *path = (*selection)[0];
  809.     if(path != NULL) {
  810.     getCamera()->viewAll(path);
  811.     }
  812.     else {
  813.     viewAll();
  814.     return;
  815.     }
  816. }
  817.  
  818.  
  819. ////////////////////////////////////////////////////////////////////////
  820. //
  821. // Description:
  822. //    Create a color editor for the currently selected object.
  823. //      Attachment code copied from SoXformManip.c++
  824. //
  825. // Use: private
  826. void
  827. SoSceneViewer::createColorEditor()
  828. //
  829. ////////////////////////////////////////////////////////////////////////
  830. {
  831.     if (colorEditor == NULL) {
  832.     colorEditor = new SoXtColorEditor;
  833.     colorEditor->setWYSIWYG(TRUE); //??? do this in app-defaults?
  834.     colorEditor->setTitle("Diffuse Color");
  835.     }
  836.  
  837.     SoMaterial *editMaterial = findMaterialForAttach( NULL );
  838.     
  839.     colorEditor->attach(&(editMaterial->diffuseColor), 0, editMaterial);
  840.  
  841.     colorEditor->show();
  842. }
  843.  
  844.  
  845. ////////////////////////////////////////////////////////////////////////
  846. //
  847. // Description:
  848. //   Find the appropriate material node in the scene graph to attach a material
  849. //   editor to.
  850. //
  851. //   Two possible cases:
  852. //        [1] The path-tail is NOT a group.  We search the siblings of the path
  853. //            tail (including the tail itself) from right to left for a node
  854. //          that is affected by materials (shapes or groups).
  855. //            We stop the search if we come to a material node to the left of the
  856. //          pathTail.  If we find a node that IS affected by material, we will
  857. //          insert a material node just before the path-tail. This is
  858. //            because the editor should not affect nodes that appear
  859. //            before attachPath in the scene graph.
  860. //        [2] The path-tail IS a group.  We search the children from left to
  861. //            right for material nodes.
  862. //            We stop the search if we come to a material node.
  863. //            If we find a node that is affected by materials, we will insert a
  864. //          material just before this node. This is because the editor for a
  865. //          group should affect ALL nodes within that group.
  866. //
  867. // NOTE: For the purposes of this routine, we consider SoSwitch as different
  868. //       from other types of group. This is because we don't want to put
  869. //       the new node underneath the switch, but next to it.
  870. //
  871. // Use: private
  872. //
  873. SoMaterial *
  874. SoSceneViewer::findMaterialForAttach(
  875.             const SoPath *target )    // path to start search from
  876. //
  877. ////////////////////////////////////////////////////////////////////////
  878. {
  879.     int         pathLength;
  880.     SoPath         *selectionPath;
  881.     SoMaterial        *editMtl;
  882.  
  883.     SbBool        madeNewMtl = FALSE; // did we create a new material
  884.                         // node within this method?
  885.  
  886.  
  887.     if ( ( selectionPath = (SoPath *) target ) == NULL ) {
  888.     //
  889.     //  If no selection path is specified, then use the LAST path in the
  890.     //  current selection list.
  891.     //
  892.     selectionPath = (*selection)[selection->getNumSelected() - 1];    // last guy
  893.     }
  894.     pathLength = selectionPath->getLength();
  895.  
  896.     if ( pathLength <= 0 ) {
  897.     fprintf( stderr, "No objects currently selected...\n" );
  898.     return NULL;
  899.     }
  900.  
  901. #ifdef DEBUG
  902.     if ( pathLength < 2 ) {
  903.     fprintf( stderr, "Picked object has no parent...\n" );
  904.     return NULL;
  905.     }
  906. #endif
  907.  
  908.  
  909.     // find 'group' and try to find 'editMtl'
  910.     SoGroup     *group;
  911.     SoNode      *node;
  912.     int         index, i;
  913.  
  914.     editMtl = NULL;
  915.  
  916.     if ( selectionPath->getTail()->isOfType( SoBaseKit::getClassTypeId() )) {
  917.     // Nodekits have their own built in policy for creating new material
  918.     // nodes. Allow them to contruct and return it.
  919.     SoBaseKit *kit = (SoBaseKit *) selectionPath->getTail();
  920.     // CHECKPART returns NULL if the part doesn't exist yet...
  921.     editMtl = CHECKPART( kit, "material", SoMaterial );
  922.     if ( editMtl == NULL ) {
  923.         editMtl = GETPART( kit, "material", SoMaterial );
  924.         madeNewMtl = TRUE;
  925.     }
  926.     }
  927.  
  928.     SbBool isTailGroup     = 
  929.       selectionPath->getTail()->isOfType( SoGroup::getClassTypeId()) &&
  930.       (!selectionPath->getTail()->isOfType( SoSwitch::getClassTypeId()));
  931.     
  932.     if ((editMtl == NULL) && ( !isTailGroup )) {
  933.     //
  934.         //    CASE 1: The path-tail is not a group.
  935.         //    'group'      becomes the second to last node in the path.
  936.         //    We search the path tail and its siblings from right to left for a
  937.         //    mtl node.
  938.         //    We stop the search if we come to a shape node or a group node
  939.         //    to the left of the pathTail.  If we find a shape or group, we
  940.         //    will insert a mtl just before the path-tail. This is
  941.         //    because the manipulator should not affect objects that appear
  942.         //    before selectionPath in the scene graph.
  943.     //
  944.         group      = (SoGroup *) selectionPath->getNode(pathLength - 2);
  945.         index      = group->findChild( selectionPath->getTail() );
  946.  
  947.         for (i = index; (i >= 0) && (editMtl == NULL); i--){
  948.             node = group->getChild(i);
  949.             if (node->isOfType(SoMaterial::getClassTypeId())) // found SoMaterial
  950.                 editMtl = (SoMaterial *) node;
  951.             else if ( i != index ) { 
  952.                 if ( isAffectedByMaterial( node ) )
  953.                     break;
  954.             }
  955.         }
  956.  
  957.         if ( editMtl == NULL ) {
  958.             editMtl = new SoMaterial;
  959.             group->insertChild( editMtl, index );
  960.         madeNewMtl = TRUE;
  961.         }
  962.     }
  963.     else if (editMtl == NULL) {
  964.         //    CASE 2: The path-tail is a group.
  965.         //    'group'      becomes the path tail
  966.         //      We search the children from left to right for mtl nodes.
  967.         //      We stop the search if we come to a shape node or a group node.
  968.         //      If we find a shape or group, we will insert a mtl just
  969.         //      before this shape or group. This is because the editor
  970.         //      for a group should affect ALL objects within that group.
  971.     //
  972.         group = (SoGroup *) selectionPath->getTail();
  973.         for (i = 0; (i < group->getNumChildren()) && (editMtl == NULL); i++ ) {
  974.             node = group->getChild(i);
  975.             if (node->isOfType(SoMaterial::getClassTypeId()))
  976.                 editMtl = (SoMaterial *) node;
  977.             else if ( isAffectedByMaterial( node ) )
  978.                 break;
  979.         }
  980.  
  981.         if ( editMtl == NULL ) {
  982.             editMtl = new SoMaterial;
  983.             group->insertChild( editMtl, i );
  984.         madeNewMtl = TRUE;
  985.         }
  986.     }
  987.  
  988.     // If we just created the material node here, then set the ignore
  989.     // flags for all fields in the node.  This will cause the fields
  990.     // to be inherited from their ancestors. The material editor will
  991.     // undo these flags whenever it changes the value of a field
  992.     if ( madeNewMtl == TRUE ) {
  993.     editMtl->ambientColor.setIgnored( TRUE );
  994.     editMtl->diffuseColor.setIgnored( TRUE );
  995.     editMtl->specularColor.setIgnored( TRUE );
  996.     editMtl->emissiveColor.setIgnored( TRUE );
  997.     editMtl->shininess.setIgnored( TRUE );
  998.     editMtl->transparency.setIgnored( TRUE );
  999.     }
  1000.  
  1001.     // If any of the fields is ignored, then fill the value with the value
  1002.     // inherited from the rest of the scene graph
  1003.     if ( editMtl->ambientColor.isIgnored() 
  1004.     || editMtl->diffuseColor.isIgnored() 
  1005.     || editMtl->specularColor.isIgnored() 
  1006.     || editMtl->emissiveColor.isIgnored() 
  1007.     || editMtl->shininess.isIgnored() 
  1008.     || editMtl->transparency.isIgnored() ){
  1009.  
  1010.     // Create a path to the material
  1011.     SoPath *mtlPath;
  1012.     if ( selectionPath->getTail()->isOfType( SoBaseKit::getClassTypeId() )) {
  1013.         SoBaseKit *kit = (SoBaseKit *) selectionPath->getTail();
  1014.         mtlPath = kit->createPathToPart( "material",
  1015.                         SoMaterial::getClassTypeId(),
  1016.                         TRUE, selectionPath );
  1017.         mtlPath->ref();
  1018.     }
  1019.     else {
  1020.         if ( !isTailGroup ) {
  1021.         // CASE 1: path-tail was NOT 'group' -- copy all but last entry
  1022.         mtlPath = new SoPath;
  1023.         mtlPath->copy(selectionPath, 0, pathLength - 1);
  1024.         }
  1025.         else {
  1026.         // CASE 2: path-tail was 'group' -- copy all of editPath
  1027.         mtlPath = new SoPath;
  1028.         mtlPath->copy(selectionPath, 0, pathLength);
  1029.         }
  1030.         mtlPath->ref();
  1031.         // add the material to the end of the path
  1032.         int mtlIndex    = group->findChild(editMtl);
  1033.         mtlPath->append( mtlIndex );
  1034.     }
  1035.  
  1036.     // Pass the material node to an accumulate state callback
  1037.     // that will load any 'ignored' values with their inherited values.
  1038.     SoCallbackAction cba;
  1039.     cba.addPreTailCallback( SoSceneViewer::findMtlPreTailCB, editMtl);
  1040.     cba.apply( mtlPath );
  1041.  
  1042.     mtlPath->unref();
  1043.     }
  1044.  
  1045.  
  1046.     return( editMtl );
  1047. }
  1048.  
  1049. ////////////////////////////////////////////////////////////////////////
  1050. //
  1051. // Description:
  1052. //   Callback used by 'findMaterialForAttach' as part of the accumulate state
  1053. //   action. Returns 'PRUNE', which tells the action not to draw the
  1054. //   shape as part of the accum state action.
  1055. //   editor to.
  1056. //
  1057. // Use: private
  1058. //
  1059. SoCallbackAction::Response
  1060. SoSceneViewer::findMtlPreTailCB( void *data, SoCallbackAction *accum, 
  1061.                  const SoNode * )
  1062. //
  1063. ////////////////////////////////////////////////////////////////////////
  1064. {
  1065.     SoMaterial *mtl = (SoMaterial *) data;
  1066.  
  1067.     SbColor ambient, diffuse, specular, emissive;
  1068.     float   shininess, transparency;
  1069.  
  1070.     accum->getMaterial( ambient, diffuse, specular, emissive, 
  1071.             shininess, transparency ); 
  1072.  
  1073.     // inherit the accumulated values only in those fields being ignored.
  1074.     if ( mtl->ambientColor.isIgnored() )
  1075.      mtl->ambientColor.setValue( ambient );
  1076.     if ( mtl->diffuseColor.isIgnored() )
  1077.      mtl->diffuseColor.setValue( diffuse );
  1078.     if ( mtl->specularColor.isIgnored() )
  1079.      mtl->specularColor.setValue( specular );
  1080.     if ( mtl->emissiveColor.isIgnored() )
  1081.      mtl->emissiveColor.setValue( emissive );
  1082.     if ( mtl->shininess.isIgnored() )
  1083.      mtl->shininess.setValue( shininess );
  1084.     if ( mtl->transparency.isIgnored() )
  1085.      mtl->transparency.setValue( transparency );
  1086.  
  1087.     return SoCallbackAction::ABORT;
  1088. }
  1089.  
  1090. ////////////////////////////////////////////////////////////////////////
  1091. //
  1092. // Description:
  1093. //   Find the appropriate transform node in the scene graph for attaching a 
  1094. //   transform editor or manipulator.
  1095. //
  1096. //   How we treat the 'center' field of the transform node:
  1097. //   If we need to create a new transform node:
  1098. //       set the 'center' to be the geometric center of all objects 
  1099. //       affected by that transform. 
  1100. //   If we find a transform node that already exists:
  1101. //       'center' will not be changed.
  1102. //
  1103. //   Three possible cases:
  1104. //        [1] The path-tail is a node kit. Just ask the node kit for a path
  1105. //            to the part called "transform"
  1106. //        [2] The path-tail is NOT a group.  We search the siblings of the path
  1107. //            tail (including the tail itself) from right to left for a node
  1108. //          that is affected by transforms (shapes, groups, lights,cameras).
  1109. //            We stop the search if we come to a transform node to the left of 
  1110. //          the pathTail.  If we find a node that IS affected by transform, 
  1111. //          we will insert a transform node just before the path-tail. This is
  1112. //            because the editor should not affect nodes that appear
  1113. //            before attachPath in the scene graph.
  1114. //        [3] The path-tail IS a group.  We search the children from left to
  1115. //            right for transform nodes.
  1116. //            We stop the search if we come to a transform node.
  1117. //            If we find a node that is affected by transform, we will insert a
  1118. //          transform just before this node. This is because the editor for a
  1119. //          group should affect ALL nodes within that group.
  1120. //
  1121. // NOTE: For the purposes of this routine, we consider SoSwitch as different
  1122. //       from other types of group. This is because we don't want to put
  1123. //       the new node underneath the switch, but next to it.
  1124. //
  1125. // Use: private
  1126. //
  1127. SoPath *
  1128. SoSceneViewer::findTransformForAttach(
  1129.             const SoPath *target )    // path to start search from
  1130. //
  1131. ////////////////////////////////////////////////////////////////////////
  1132. {
  1133.     int         pathLength;
  1134.     SoPath         *selectionPath;
  1135.     SoTransform        *editXform;
  1136.  
  1137.     
  1138.     if ( ( selectionPath = (SoPath *) target ) == NULL ) {
  1139.     //
  1140.     //  If no selection path is specified, then use the LAST path in the
  1141.     //  current selection list.
  1142.     //
  1143.     selectionPath = (*selection)[selection->getNumSelected() - 1];
  1144.     }
  1145.     pathLength = selectionPath->getLength();
  1146.  
  1147.     if ( pathLength <= 0 ) {
  1148.     fprintf( stderr, "No objects currently selected...\n" );
  1149.     return NULL;
  1150.     }
  1151.  
  1152. #ifdef DEBUG
  1153.     if ( pathLength < 2 ) {
  1154.     fprintf( stderr, "Picked object has no parent...\n" );
  1155.     return NULL;
  1156.     }
  1157. #endif
  1158.  
  1159.     // find 'group' and try to find 'editXform'
  1160.     SoGroup     *group;
  1161.     SoNode      *node;
  1162.     int         index, i;
  1163.     SbBool      isTailGroup,  isTailKit;
  1164.     SbBool      existedBefore = FALSE;
  1165.     SoPath      *pathToXform = NULL;
  1166.  
  1167.     editXform = NULL;
  1168.  
  1169.     isTailGroup =
  1170.         (   selectionPath->getTail()->isOfType(SoGroup::getClassTypeId() )
  1171.         && !selectionPath->getTail()->isOfType(SoSwitch::getClassTypeId()));
  1172.  
  1173.     isTailKit = selectionPath->getTail()->isOfType(SoBaseKit::getClassTypeId());
  1174.  
  1175.     //    CASE 1: The path-tail is a node kit.
  1176.     if ( isTailKit ) {
  1177.  
  1178.     // Nodekits have their own built in policy for creating new transform
  1179.     // nodes. Allow them to contruct and return a path to it.
  1180.     SoBaseKit *kit = (SoBaseKit *) selectionPath->getTail();
  1181.  
  1182.     // Before creating path, see if the transform part exists yet:
  1183.     if (CHECKPART(kit, "transform", SoTransform) != NULL)
  1184.         existedBefore = TRUE;
  1185.     else
  1186.         existedBefore = FALSE;
  1187.  
  1188.     pathToXform = kit->createPathToPart( "transform",
  1189.                     SoTransform::getClassTypeId(),
  1190.                     TRUE, selectionPath );
  1191.     pathToXform->ref();
  1192.  
  1193.     editXform = (SoTransform *) pathToXform->getTail();
  1194.     }
  1195.     
  1196.     if ( !isTailGroup && !isTailKit ) {
  1197.     //
  1198.         //    CASE 2: The path-tail is not a group.
  1199.         //    'group'      becomes the second to last node in the path.
  1200.         //    We search the path tail and its siblings from right to left for a
  1201.         //    transform node.
  1202.         //    We stop the search if we come to a 'movable' node
  1203.         //    to the left of the pathTail.  If we find a movable node, we
  1204.         //    will insert a transform just before the path-tail. This is
  1205.         //    because the manipulator should not affect objects that appear
  1206.         //    before selectionPath in the scene graph.
  1207.     //
  1208.         group      = (SoGroup *) selectionPath->getNode(pathLength - 2);
  1209.         index      = group->findChild( selectionPath->getTail() );
  1210.  
  1211.         for (i = index; (i >= 0) && (editXform == NULL); i--){
  1212.             node = group->getChild(i);
  1213.             if (node->isOfType(SoTransform::getClassTypeId()))  // found an SoMaterial
  1214.                 editXform = (SoTransform *) node;
  1215.             else if ( i != index ) { 
  1216.         if ( !node->isOfType( SoManipulator::getClassTypeId() ) ) {
  1217.             if ( isAffectedByTransform( node ) )
  1218.             break;
  1219.         }
  1220.             }
  1221.         }
  1222.  
  1223.         if ( editXform == NULL ) {
  1224.         existedBefore = FALSE;
  1225.             editXform = new SoTransform;
  1226.             group->insertChild( editXform, index );
  1227.         }
  1228.     else
  1229.         existedBefore = TRUE;
  1230.     }
  1231.     else if ( !isTailKit ) {
  1232.         //    CASE 3: The path-tail is a group.
  1233.         //    'group'      becomes the path tail
  1234.         //      We search the children from left to right for transform nodes.
  1235.         //      We stop the search if we come to a movable node.
  1236.         //      If we find a movable node, we will insert a transform just
  1237.         //      before this node. This is because the editor
  1238.         //      for a group should affect ALL objects within that group.
  1239.     //
  1240.         group = (SoGroup *) selectionPath->getTail();
  1241.         for (i = 0; (i < group->getNumChildren()) && (editXform == NULL); i++ ) {
  1242.             node = group->getChild(i);
  1243.             if (node->isOfType(SoTransform::getClassTypeId()))
  1244.                 editXform = (SoTransform *) node;
  1245.             else if ( isAffectedByTransform( node ) )
  1246.                 break;
  1247.         }
  1248.  
  1249.         if ( editXform == NULL ) {
  1250.         existedBefore = FALSE;
  1251.             editXform = new SoTransform;
  1252.             group->insertChild( editXform, i );
  1253.         }
  1254.     else
  1255.         existedBefore = TRUE;
  1256.     }
  1257.  
  1258.     // If we don't have a path yet (i.e., we weren't handed a nodekit path)
  1259.     // create the 'pathToXform'
  1260.     // by copying editPath and making the last node in the path be editXform
  1261.     if ( pathToXform == NULL ) {
  1262.     pathToXform = new SoPath;
  1263.     pathToXform->ref();
  1264.     if ( !isTailGroup )
  1265.         // CASE 2: path-tail was NOT 'group' -- copy all but last entry
  1266.         pathToXform->copy(selectionPath, 0, pathLength - 1);
  1267.     else
  1268.         // CASE 3: path-tail was 'group' -- copy all of editPath
  1269.         pathToXform->copy(selectionPath, 0, pathLength);
  1270.     // add the transform to the end
  1271.     int xfIndex    = group->findChild(editXform);
  1272.     pathToXform->append( xfIndex );
  1273.     }
  1274.  
  1275.  
  1276.     // Now. If we created the transform node right here, right now, then
  1277.     // we will set the 'center' field based on the geometric center. We 
  1278.     // don't do this if we didn't create the transform, because "maybe it
  1279.     // was that way for a reason."
  1280.     if ( existedBefore == FALSE ) {
  1281.     // First, find 'applyPath' by popping nodes off the path until you 
  1282.     // reach a separator. This path will contain all nodes affected by
  1283.     // the transform at the end of 'pathToXform'
  1284.     SoPath *applyPath = new SoPath;
  1285.     applyPath->ref();
  1286.     applyPath->copy(pathToXform);
  1287.     for (int i = (applyPath->getLength() - 1); i >0; i-- ) {
  1288.         if (applyPath->getNode(i)->isOfType( SoSeparator::getClassTypeId()))
  1289.         break;
  1290.         applyPath->pop();
  1291.     }
  1292.  
  1293.     // Next, apply a bounding box action to applyPath, and reset the
  1294.     // bounding box just before the tail of 'pathToXform' (which is just
  1295.     // the editXform). This will assure that the only things included in 
  1296.     // the resulting bbox will be those affected by the editXform.
  1297.     SoGetBoundingBoxAction bboxAction;
  1298.     bboxAction.setResetPath(pathToXform,TRUE,SoGetBoundingBoxAction::BBOX );
  1299.     bboxAction.apply(applyPath);
  1300.  
  1301.     // Get the center of the bbox in world space...
  1302.     SbVec3f worldBoxCenter = bboxAction.getBoundingBox().getCenter();
  1303.  
  1304.     // Convert it into local space of the transform...
  1305.     SbVec3f localBoxCenter;
  1306.     SoGetMatrixAction ma;
  1307.     ma.apply( pathToXform );
  1308.     ma.getInverse().multVecMatrix( worldBoxCenter, localBoxCenter );
  1309.  
  1310.     // Finally, set the center value...
  1311.     editXform->center.setValue( localBoxCenter );
  1312.     }
  1313.  
  1314.     return( pathToXform );
  1315. }
  1316.  
  1317.  
  1318. ////////////////////////////////////////////////////////////////////////
  1319. //
  1320. // Description:
  1321. //    Create a material editor for the currently selected object.
  1322. //
  1323. // Use: private
  1324. void
  1325. SoSceneViewer::createMaterialEditor()
  1326. //
  1327. ////////////////////////////////////////////////////////////////////////
  1328. {
  1329.     if (materialEditor == NULL)
  1330.         materialEditor = new SoXtMaterialEditor;
  1331.     materialEditor->show();
  1332.     
  1333.     materialEditor->attach( findMaterialForAttach( NULL ) );
  1334. }
  1335.  
  1336. ////////////////////////////////////////////////////////////////////////
  1337. //
  1338. // Description:
  1339. //    Create a transform editor for the currently selected object
  1340. //
  1341. // Use: private
  1342. void
  1343. SoSceneViewer::createTransformSliderSet()
  1344. //
  1345. ////////////////////////////////////////////////////////////////////////
  1346. {
  1347.     SoPath      *editTransformPath;
  1348.     SoTransform *editTransform;
  1349.  
  1350.     // get path to a transform to edit
  1351.     if ( ( editTransformPath = findTransformForAttach( NULL )) == NULL )
  1352.     return;
  1353.  
  1354.     // the tail of the path is a transform for us!
  1355.     editTransformPath->ref();
  1356.     editTransform = (SoTransform *) editTransformPath->getTail();
  1357.     editTransformPath->unref();
  1358.     
  1359.     // Nuke the old slider set and get a new one
  1360.     if (transformSliderSet == NULL)
  1361.     transformSliderSet = new SoXtTransformSliderSet();
  1362.     transformSliderSet->build();
  1363.     transformSliderSet->setNode(editTransform);
  1364.     transformSliderSet->show();
  1365. }
  1366.  
  1367. ////////////////////////////////////////////////////////////////////////
  1368. //
  1369. // Description:
  1370. //      Set fog on/off.
  1371. //
  1372. // Use: private
  1373. void
  1374. SoSceneViewer::setFog(SbBool flag)
  1375. //
  1376. ////////////////////////////////////////////////////////////////////////
  1377. {
  1378.     fogFlag = flag;
  1379.     
  1380.     if (fogFlag)
  1381.         environment->fogType.setValue( SoEnvironment::EXPONENTIAL );
  1382.     else
  1383.         environment->fogType.setValue( SoEnvironment::NONE );
  1384.     
  1385.     // ??? set the density here instead of the constructor because the
  1386.     // ??? farDistance doesn't have meaningful values untill the viewers
  1387.     // ??? change it (autoClipping).
  1388.     environment->fogDensity.setValue( 1.0
  1389.         / (FOG_FUDGE * getCamera()->farDistance.getValue()) );
  1390. }
  1391.  
  1392. ////////////////////////////////////////////////////////////////////////
  1393. //
  1394. // Description:
  1395. //      Set AA-ing on/off.
  1396. //
  1397. // Use: private
  1398. void
  1399. SoSceneViewer::setAntialiasing(SbBool flag)
  1400. //
  1401. ////////////////////////////////////////////////////////////////////////
  1402. {
  1403.     antialiasingFlag = flag;
  1404.     
  1405.     if (antialiasingFlag)
  1406.     currentViewer->setAntialiasing( TRUE, 3 );
  1407.     else
  1408.     currentViewer->setAntialiasing( FALSE, 1 );
  1409.     
  1410.     sceneGraph->notify( NULL );  // forces a redraw
  1411. }
  1412.  
  1413. ////////////////////////////////////////////////////////////////////////
  1414. //
  1415. // Description:
  1416. //      Invokes color editor on ambient lighting color.
  1417. void
  1418. SoSceneViewer::editAmbientColor()
  1419. //
  1420. ////////////////////////////////////////////////////////////////////////
  1421.     if ( ambientColorEditor == NULL ) {
  1422.         ambientColorEditor = new SoXtColorEditor;
  1423.     ambientColorEditor->setTitle( "Ambient Lighting" );
  1424.     ambientColorEditor->addColorChangedCallback(
  1425.         SoSceneViewer::ambientColorCallback, this );
  1426.     }
  1427.     
  1428.     // Normalize ambient intensity
  1429.     SbColor ambCol;
  1430.     ambCol = environment->ambientColor.getValue();
  1431.     ambCol *= environment->ambientIntensity.getValue();
  1432.     environment->ambientIntensity.setValue( 1.0 );
  1433.     environment->ambientColor.setValue( ambCol );
  1434.     
  1435.     ignoreCallback = TRUE;
  1436.     ambientColorEditor->setColor( environment->ambientColor.getValue() );
  1437.     ignoreCallback = FALSE;
  1438.     ambientColorEditor->show();
  1439. }
  1440.  
  1441. ////////////////////////////////////////////////////////////////////////
  1442. //
  1443. // Description:
  1444. //  Callback proc invoked by the color editor, this changes the scene's
  1445. //  ambient lighting color.
  1446. //
  1447. //  Use: static, private
  1448. //
  1449. void
  1450. SoSceneViewer::ambientColorCallback(void *userData, const SbColor *color)
  1451. //
  1452. ////////////////////////////////////////////////////////////////////////
  1453. {
  1454.     SoSceneViewer *sv = (SoSceneViewer *) userData;
  1455.     
  1456.     if (sv->ignoreCallback)
  1457.         return;
  1458.     
  1459.     sv->environment->ambientColor.setValue( *color );
  1460. }
  1461.  
  1462. ////////////////////////////////////////////////////////////////////////
  1463. //
  1464. // Description:
  1465. //      Invokes color editor on background color.
  1466. void
  1467. SoSceneViewer::editBackgroundColor()
  1468. //
  1469. ////////////////////////////////////////////////////////////////////////
  1470.     if ( backgroundColorEditor == NULL ) {
  1471.         backgroundColorEditor = new SoXtColorEditor;
  1472.     backgroundColorEditor->setTitle( "Background Color" );
  1473.     backgroundColorEditor->addColorChangedCallback(
  1474.         SoSceneViewer::backgroundColorCallback, this );
  1475.     }
  1476.     ignoreCallback = TRUE;
  1477.     backgroundColorEditor->setColor(getBackgroundColor());
  1478.     ignoreCallback = FALSE;
  1479.     backgroundColorEditor->show();
  1480. }
  1481.  
  1482. ////////////////////////////////////////////////////////////////////////
  1483. //
  1484. // Description:
  1485. //  Callback proc invoked by the color editor, this changes the current
  1486. //  viewer's background color.
  1487. //
  1488. //  Use: static, private
  1489. //
  1490. void
  1491. SoSceneViewer::backgroundColorCallback(void *userData, const SbColor *c)
  1492. //
  1493. ////////////////////////////////////////////////////////////////////////
  1494. {
  1495.     SoSceneViewer *sv = (SoSceneViewer *) userData;
  1496.     
  1497.     if (sv->ignoreCallback)
  1498.         return;
  1499.     
  1500.     sv->currentViewer->setBackgroundColor( *c );
  1501.     
  1502.     // keep fog color up to date with bkg color
  1503.     sv->environment->fogColor.setValue( *c );
  1504. }
  1505.  
  1506. ////////////////////////////////////////////////////////////////////////
  1507. //
  1508. // Description:
  1509. //    This will remove any cameras under root.
  1510. //
  1511. // Use: private
  1512. void
  1513. SoSceneViewer::removeCameras(SoGroup *root)
  1514. //
  1515. ////////////////////////////////////////////////////////////////////////
  1516. {
  1517.     SoSearchAction sa;
  1518.     sa.setType(SoCamera::getClassTypeId());
  1519.     sa.setFindAll(TRUE);
  1520.     sa.apply(root);
  1521.     
  1522.     // remove those cameras!
  1523.     SoPathList paths = sa.getPaths();
  1524.     for (int i = 0; i < paths.length(); i++) {
  1525.     SoPath *p = paths[i];
  1526.     SoCamera *cam = (SoCamera *) p->getNodeFromTail(0);
  1527.     SoGroup  *group = (SoGroup *) p->getNodeFromTail(1);
  1528.     group->removeChild(cam);
  1529.     }
  1530. }
  1531.  
  1532. ////////////////////////////////////////////////////////////////////////
  1533. //
  1534. // Description:
  1535. //    Reads the given file and insert the geometry under the selection
  1536. //  node. If the node didn't have any children, the viewAll() method is
  1537. //  automatically called.
  1538. //
  1539. // Use: private
  1540. SbBool
  1541. SoSceneViewer::readFile(const char *filename)
  1542. //
  1543. ////////////////////////////////////////////////////////////////////////
  1544. {
  1545.     SoInput in;
  1546.     if (! in.openFile(filename)) {
  1547.     
  1548.     // display an error dialog
  1549.     char str[100];
  1550.     strcpy(str, "Error opening file: ");
  1551.     strcat(str, filename);
  1552.     SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  1553.     return FALSE;
  1554.     }
  1555.     
  1556.     SbBool hadNoChildren = (selection->getNumChildren() == 0);
  1557.     
  1558.     // add nodes under selection, not sceneGraph
  1559.     SoNode *node;
  1560.     SbBool ok;
  1561.     while ((ok = SoDB::read(&in, node)) && (node != NULL))
  1562.     selection->addChild(node);
  1563.     
  1564.     // display error dialog if there were reading errors
  1565.     if (!ok) {
  1566.     char str[100];
  1567.     strcpy(str, "Error reading file: ");
  1568.     strcat(str, filename);
  1569.     SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  1570.     return FALSE;
  1571.     }
  1572.     
  1573.     // remove any cameras under selection which were just added
  1574.     removeCameras(selection);
  1575.     
  1576.     if (hadNoChildren) {
  1577.     viewAll();
  1578.     saveHomePosition();
  1579.     }
  1580.     
  1581.     return TRUE;
  1582. }
  1583.  
  1584. ////////////////////////////////////////////////////////////////////////
  1585. //
  1586. // Description:
  1587. //    Read environment data. We expect the following nodes:
  1588. //
  1589. //  Group {
  1590. //    Label { "SoSceneViewer Environment v3.0" }
  1591. //    Camera {}
  1592. //    Environment {}
  1593. //    LightGroup {
  1594. //      Switch { DirectionalLight }  # 1
  1595. //      ...
  1596. //      Switch { DirectionalLight }  # 6
  1597. //    }
  1598. //    DirectionalLight {}       # optional headlight
  1599. //  }
  1600. //
  1601. // Use: private
  1602. SbBool
  1603. SoSceneViewer::readEnvFile(const char *filename)
  1604. //
  1605. ////////////////////////////////////////////////////////////////////////
  1606. {
  1607.     SoInput in;
  1608.     SoNode *n;
  1609.     SoGroup *g = NULL;
  1610.     SoLabel *l = NULL;
  1611.     SbBool isValid = FALSE;
  1612.     SbBool ok=FALSE;
  1613. while(!ok) 
  1614.    {
  1615.     if (! in.openFile(filename)) {
  1616.     // display an error dialog
  1617.     char str[100];
  1618.     strcpy(str, "Error opening file: ");
  1619.     strcat(str, filename);
  1620.     SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  1621.     return FALSE;
  1622.     }
  1623.     
  1624.     
  1625.     if ((ok = SoDB::read(&in, n)) && n != NULL) {
  1626.     // we expect a label first
  1627.     n->ref();
  1628.     if (n->isOfType(SoLabel::getClassTypeId())) {
  1629.         l = (SoLabel *) n;
  1630.         isValid = (strcmp(l->label.getValue().getString(),
  1631.                   SV_ENV_LABEL) == 0);
  1632.     }
  1633.     n->unref();
  1634.     }
  1635.   }
  1636. //    else if (!ok) {
  1637.      //display error dialog if there were reading errors
  1638. //    char str[100];
  1639. //    strcpy(str, "Error reading file: ");
  1640. //    strcat(str, filename);
  1641. //    SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  1642. //    return FALSE;
  1643. //   }
  1644.  
  1645.     // if ok, read the rest.
  1646.     if (isValid) {
  1647.     // Camera
  1648.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  1649.         n->ref();
  1650.         if (n->isOfType(SoPerspectiveCamera::getClassTypeId())) {
  1651.         // viewers need to be detached from the old camera
  1652.         // and attached to the new. both cameras must be in
  1653.         // the scene graph for this to happen smoothly.
  1654.         SoPerspectiveCamera *newCamera = (SoPerspectiveCamera *) n;
  1655.         lightsCameraEnvironment->insertChild(newCamera, 0);
  1656.         setCamera(newCamera);
  1657.         lightsCameraEnvironment->removeChild(camera);
  1658.         camera = newCamera;            
  1659.         }
  1660.         n->unref();
  1661.     }
  1662.     // Environment
  1663.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  1664.         n->ref();
  1665.         if (n->isOfType(SoEnvironment::getClassTypeId())) {
  1666.         lightsCameraEnvironment->replaceChild(environment, n);
  1667.         environment = (SoEnvironment *) n;
  1668.         }
  1669.         n->unref();
  1670.     }
  1671.     // Light group
  1672.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  1673.         n->ref();
  1674.         if (n->isOfType(SoGroup::getClassTypeId())) {
  1675.         
  1676.         // remove all of the existing lights
  1677.         for (int i = lightDataList.length(); i > 0; i--)
  1678.             removeLight( (SvLightData *) lightDataList[i-1] );
  1679.         
  1680.         lightsCameraEnvironment->replaceChild(lightGroup, n);
  1681.         lightGroup = (SoGroup *) n;
  1682.         
  1683.         // now create a light entry for each new light
  1684.         for (i=0; i < lightGroup->getNumChildren(); i++) {
  1685.             SoNode *node = lightGroup->getChild(i);
  1686.             if (node->isOfType(SoSwitch::getClassTypeId())) {
  1687.             SoSwitch *sw = (SoSwitch *) node;
  1688.             node = sw->getChild(0);
  1689.             if (node->isOfType(SoLight::getClassTypeId()))
  1690.                 addLightEntry((SoLight *)node, sw);
  1691.             }
  1692.         }
  1693.         }
  1694.         n->unref();
  1695.     }
  1696.     // Headlight (optional) - if not there, turn headlight off
  1697.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  1698.         n->ref();
  1699.         if (n->isOfType(SoDirectionalLight::getClassTypeId())) {
  1700.         SoDirectionalLight *headlight = getHeadlight();
  1701.         SoDirectionalLight *newLight = (SoDirectionalLight *) n;
  1702.         headlight->intensity.setValue(newLight->intensity.getValue());
  1703.         headlight->color.setValue(newLight->color.getValue());
  1704.         headlight->direction.setValue(newLight->direction.getValue());
  1705.         setHeadlight(TRUE);
  1706.         }
  1707.         n->unref();
  1708.     }
  1709.     else setHeadlight(FALSE);
  1710.     }
  1711.     else {
  1712.     fprintf(stderr, "Sorry, file is not formatted correctly\n");
  1713.     }
  1714.     
  1715.     return TRUE;
  1716. }
  1717.  
  1718. ////////////////////////////////////////////////////////////////////////
  1719. //
  1720. // Description:
  1721. //    This routine is called to get a file name. Either a motif 
  1722. //  dialog or the showcase gizmo are used.
  1723. //
  1724. // Use: private
  1725. void
  1726. SoSceneViewer::getFileName()
  1727. //
  1728. ////////////////////////////////////////////////////////////////////////
  1729. {
  1730.     if ( useShowcaseBrowser ) {
  1731.     // use the showcase browser
  1732.     if (browser == NULL) {
  1733.         browser = new SoXtFileBrowser;
  1734.         browser->setCallback(SoSceneViewer::browserCB, this);
  1735.     }
  1736.     
  1737.     if (browser->isVisible())
  1738.         browser->hide();
  1739.     
  1740.     browser->show();
  1741.     }
  1742.     else {
  1743.     // use a motif file selection dialog
  1744.     if (fileDialog == NULL) {
  1745.         Arg args[5];
  1746.         int n = 0;
  1747.         
  1748.         // unmanage when ok/cancel are pressed
  1749.         XtSetArg(args[n], XmNautoUnmanage, TRUE); n++;
  1750.         fileDialog = XmCreateFileSelectionDialog(
  1751.         XtParent(mgrWidget), "File Dialog", args, n);
  1752.         
  1753.         XtAddCallback(fileDialog, XmNokCallback,
  1754.               (XtCallbackProc)SoSceneViewer::fileDialogCB,
  1755.               (XtPointer)this);
  1756.     }
  1757.     
  1758.     // manage the dialog
  1759.     XtManageChild(fileDialog);
  1760.     }
  1761. }
  1762.  
  1763. ////////////////////////////////////////////////////////////////////////
  1764. //
  1765. // Description:
  1766. //    Showcase browser gizmo callback.
  1767. //
  1768. void
  1769. SoSceneViewer::browserCB(void *sv, const char *filename)
  1770. //
  1771. ////////////////////////////////////////////////////////////////////////
  1772. {
  1773.     ((SoSceneViewer *)sv)->doFileIO(filename);
  1774. }
  1775.  
  1776. ////////////////////////////////////////////////////////////////////////
  1777. //
  1778. // Description:
  1779. //    Motif file dialog callback.
  1780. //
  1781. void
  1782. SoSceneViewer::fileDialogCB(Widget, SoSceneViewer *sv,
  1783.               XmFileSelectionBoxCallbackStruct *data)
  1784. //
  1785. ////////////////////////////////////////////////////////////////////////
  1786. {
  1787.     // Get the file name
  1788.     char *filename;
  1789.     XmStringGetLtoR(data->value,
  1790.     (XmStringCharSet) XmSTRING_DEFAULT_CHARSET, &filename);
  1791.     
  1792.     // Use that file
  1793.     sv->doFileIO(filename);
  1794.     
  1795.     XtFree(filename);
  1796. }
  1797.  
  1798. ////////////////////////////////////////////////////////////////////////
  1799. //
  1800. // Description:
  1801. //    detach everything and nuke the existing scene.
  1802. //
  1803. // Use: private
  1804. void
  1805. SoSceneViewer::deleteScene()
  1806. //
  1807. ////////////////////////////////////////////////////////////////////////
  1808. {
  1809.     // deselect everything (also detach manips)
  1810.     selection->deselectAll();
  1811.     
  1812.     // temporaly remove the light manips
  1813.     removeAttachedLightManipGeometry();
  1814.     
  1815.     // remove the geometry under the selection node
  1816.     for (int i = selection->getNumChildren(); i>0; i--)
  1817.     selection->removeChild(i-1);
  1818.     
  1819.     // add the light manips back in
  1820.     addAttachedLightManipGeometry();
  1821. }
  1822.  
  1823. ////////////////////////////////////////////////////////////////////////
  1824. //
  1825. // Description:
  1826. //    Read/Write to the given file name, given the current file mode.
  1827. //
  1828. // Use: private
  1829. void
  1830. SoSceneViewer::doFileIO(const char *file)
  1831. //
  1832. ////////////////////////////////////////////////////////////////////////
  1833. {
  1834.     SbBool okFile;
  1835.     
  1836.     switch (fileMode) {
  1837.     case SV_FILE_OPEN:
  1838.         deleteScene();
  1839.         okFile = readFile(file);
  1840.         break;
  1841.     case SV_FILE_IMPORT:
  1842.         okFile = readFile(file);
  1843.         break;
  1844.     case SV_FILE_SAVE_AS:
  1845.         okFile = writeFile(file);
  1846.         break;
  1847.     case SV_FILE_READ_ENV:
  1848.         readEnvFile(file);
  1849.         break;
  1850.     case SV_FILE_SAVE_ENV:
  1851.         writeEnvFile(file);
  1852.         break;
  1853.     default:
  1854.         fprintf(stderr, "Wrong file mode %d passed!\n", fileMode);
  1855.         return;
  1856.     }
  1857.     
  1858.     // save the new file name so we can simply use "Save" instead of
  1859.     // "Save As" next time around.
  1860.     if (fileMode == SV_FILE_OPEN || fileMode == SV_FILE_SAVE_AS) {
  1861.     
  1862.     // save the current file name
  1863.     delete fileName;
  1864.     if (okFile && file != NULL)
  1865.         fileName = strdup(file);
  1866.     else
  1867.         fileName = NULL;
  1868.     }
  1869.     
  1870.     // enable/disable cmd key shortcuts and menu items
  1871.     updateCommandAvailability();
  1872. }
  1873.  
  1874. ////////////////////////////////////////////////////////////////////////
  1875. //
  1876. // Description:
  1877. //    Saves the scene to the current file.
  1878. //
  1879. // Use: private
  1880. void
  1881. SoSceneViewer::save()
  1882. //
  1883. ////////////////////////////////////////////////////////////////////////
  1884. {
  1885.     if (fileName != NULL) {
  1886.     SbBool ok = writeFile(fileName);
  1887.     if (!ok) {
  1888.         delete fileName;
  1889.         fileName = NULL;
  1890.     }
  1891.     }
  1892.     else {
  1893.     fileMode = SV_FILE_SAVE_AS;
  1894.     getFileName();
  1895.     }
  1896. }
  1897.  
  1898. ////////////////////////////////////////////////////////////////////////
  1899. //
  1900. // Description:
  1901. //    Removes the attached light manips geometry from the scene. This
  1902. //  is used for file writting,...
  1903. //
  1904. // Use: private
  1905. void
  1906. SoSceneViewer::removeAttachedLightManipGeometry()
  1907. //
  1908. ////////////////////////////////////////////////////////////////////////
  1909. {
  1910.     SoManipulator   *manip;
  1911.     int            index;
  1912.     
  1913.     for (int i = 0; i < lightDataList.length(); i++ ) {
  1914.     manip = ((SvLightData *) lightDataList[i])->manip;
  1915.     
  1916.     // check to make sure the manip has been added to the scene
  1917.     if ( manip != NULL && (index = selection->findChild(manip)) >= 0)
  1918.         selection->removeChild( index );
  1919.     }
  1920. }
  1921.  
  1922. ////////////////////////////////////////////////////////////////////////
  1923. //
  1924. // Description:
  1925. //    Add the attached light manips geometry back into the scene. This
  1926. // is called after the geometry has been temporaly revomed (used for file
  1927. // writting).
  1928. //
  1929. // Use: private
  1930. void
  1931. SoSceneViewer::addAttachedLightManipGeometry()
  1932. //
  1933. ////////////////////////////////////////////////////////////////////////
  1934. {
  1935.     SoManipulator   *manip;
  1936.     
  1937.     for (int i = 0; i < lightDataList.length(); i++ ) {
  1938.     manip = ((SvLightData *) lightDataList[i])->manip;
  1939.     
  1940.     // check to make sure the manip was previously in the
  1941.     // scene (i.e. attached to a light).
  1942.     if ( manip != NULL && manip->isAttached() && 
  1943.         selection->findChild(manip) < 0)
  1944.         selection->addChild( manip );
  1945.     }
  1946. }
  1947.  
  1948. ////////////////////////////////////////////////////////////////////////
  1949. //
  1950. // Description:
  1951. //    Write the nodes under the selection node to the given file name.
  1952. //
  1953. // Use: private
  1954. SbBool
  1955. SoSceneViewer::writeFile(const char *filename)
  1956. //
  1957. ////////////////////////////////////////////////////////////////////////
  1958. {
  1959.     SoWriteAction   wa;
  1960.     SoManipulator   *manip;
  1961.     
  1962.     if (! wa.getOutput()->openFile(filename)) {
  1963.     
  1964.     // display an error dialog
  1965.     char str[100];
  1966.     strcpy(str, "Error creating file: ");
  1967.     strcat(str, filename);
  1968.     SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  1969.     
  1970.     return FALSE;
  1971.     }
  1972.     
  1973.     // temporarily remove all manips from the scene graph.
  1974.     // You can leave them attached, just make sure they don't write out.
  1975.     for (int m = 0; m < maniplist->getLength(); m++ ) {
  1976.     manip = maniplist->getManip(m);    
  1977.     selection->removeChild(manip);
  1978.     }
  1979.  
  1980.     // Do the same for all the light manips
  1981.     removeAttachedLightManipGeometry();
  1982.     
  1983.     // write out all the children of the selection node
  1984.     for (int i = 0; i < selection->getNumChildren(); i++)
  1985.     wa.apply(selection->getChild(i));
  1986.     wa.getOutput()->closeFile();
  1987.     
  1988.     // Now put the manips back in the scene graph.
  1989.     for ( m = 0; m < maniplist->getLength(); m++ ) {
  1990.     manip = maniplist->getManip(m);    
  1991.     selection->addChild(manip);
  1992.     }
  1993.     
  1994.     // put the light manips back in the scene graph.
  1995.     addAttachedLightManipGeometry();
  1996.     
  1997.     return TRUE;
  1998. }
  1999.  
  2000. ////////////////////////////////////////////////////////////////////////
  2001. //
  2002. // Description:
  2003. //    Write the Enviroment nodes (camera and lights) to the given 
  2004. //  file name.
  2005. //
  2006. // Use: private
  2007. SbBool
  2008. SoSceneViewer::writeEnvFile(const char *filename)
  2009. //
  2010. ////////////////////////////////////////////////////////////////////////
  2011. {
  2012.     SoWriteAction    wa;
  2013.     
  2014.     if (! wa.getOutput()->openFile(filename)) {
  2015.     
  2016.     // display an error dialog
  2017.     char str[100];
  2018.     strcpy(str, "Error creating file: ");
  2019.     strcat(str, filename);
  2020.     SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  2021.     
  2022.     return FALSE;
  2023.     }
  2024.     
  2025.     // write out the environment including the headlight
  2026.     wa.apply(envLabel);
  2027.     wa.apply(camera);
  2028.     wa.apply(environment);
  2029.     wa.apply(lightGroup);
  2030.     if (isHeadlight())
  2031.     wa.apply(getHeadlight());
  2032.     
  2033.     wa.getOutput()->closeFile();
  2034.     
  2035.     return TRUE;
  2036. }
  2037.  
  2038. ////////////////////////////////////////////////////////////////////////
  2039. //
  2040. // Description:
  2041. //    Print the scene using a custom print dialog.
  2042. //
  2043. // Use: private
  2044. void
  2045. SoSceneViewer::print()
  2046. //
  2047. ////////////////////////////////////////////////////////////////////////
  2048. {
  2049.     if (printDialog == NULL) {
  2050.        printDialog = new SoXtPrintDialog;
  2051.     printDialog->setTitle("SceneViewer Printing");
  2052.     printDialog->addBeforePrintCallback(
  2053.         SoSceneViewer::beforePrintCallback, (void *) this);
  2054.     printDialog->addAfterPrintCallback(
  2055.         SoSceneViewer::afterPrintCallback, (void *) this);
  2056.    }
  2057.   
  2058.  printDialog->show();
  2059. //printScreen(mysv);
  2060. }
  2061.  
  2062. ////////////////////////////////////////////////////////////////////////
  2063. //
  2064. // Description:
  2065. //    Temporarily remove highlighting and manips from the scene. They
  2066. // will all be restored after the printing is done.
  2067. //
  2068. // Use: private, static
  2069. void
  2070. SoSceneViewer::beforePrintCallback(void *uData, SoXtPrintDialog *)
  2071. //
  2072. ////////////////////////////////////////////////////////////////////////
  2073. {
  2074.     SoSceneViewer *sv = (SoSceneViewer *)uData;
  2075.     
  2076.     // temporarily remove all manips from the scene graph.
  2077.     // You can leave them attached, just make sure they don't write out.
  2078.     for (int m = 0; m < sv->maniplist->getLength(); m++ )
  2079.     sv->selection->removeChild( sv->maniplist->getManip(m) );
  2080.  
  2081.     // Do the same for all the light manips
  2082.     sv->removeAttachedLightManipGeometry();
  2083.     
  2084.     // remove the hilighting (saving the current highlight style)
  2085.     sv->savedHighlight = sv->selection->getHighlightStyle();
  2086.     sv->selection->setHighlightStyle(NULL);
  2087.     
  2088.     // if the current viewer is the examiner viewer, turn the 
  2089.     // feedback axis off while we print
  2090.     if (sv->whichViewer == SV_VWR_EXAMINER) {
  2091.     SoXtExaminerViewer *exam = (SoXtExaminerViewer *) sv->currentViewer;
  2092.     sv->feedbackShown = exam->isFeedbackVisible();
  2093.     exam->setFeedbackVisibility(FALSE);
  2094.     }
  2095.     
  2096.     //
  2097.     // Send the render area size and scene graph to the print dialog
  2098.     //
  2099.     Widget widget = sv->getRenderAreaWidget();
  2100.     if (widget != NULL) {
  2101.         Arg args[2];
  2102.         int n = 0;
  2103.         short _w, _h;   // HAS to be shorts
  2104.         XtSetArg(args[n], XtNheight, &_h); n++;
  2105.         XtSetArg(args[n], XtNwidth, &_w); n++;
  2106.         XtGetValues(widget, args, n);
  2107.         sv->printDialog->setPrintSize((int)_w, (int)_h);
  2108.     }
  2109.     
  2110.     // set the scene to print
  2111.     sv->printDialog->setSceneGraph(sv->sceneGraph);
  2112. }
  2113.  
  2114. ////////////////////////////////////////////////////////////////////////
  2115. //
  2116. // Description:
  2117. //    Called after printing is done. Add the manips back into the
  2118. // scene and restore the highliting style.
  2119. //
  2120. // Use: private, static
  2121. void
  2122. SoSceneViewer::afterPrintCallback(void *uData, SoXtPrintDialog *)
  2123. //
  2124. ////////////////////////////////////////////////////////////////////////
  2125. {
  2126.     SoSceneViewer *sv = (SoSceneViewer *)uData;
  2127.     
  2128.     // put the manips back in the scene graph.
  2129.     for (int m = 0; m < sv->maniplist->getLength(); m++ )
  2130.     sv->selection->addChild( sv->maniplist->getManip(m) );
  2131.     
  2132.     // put the light manips back in the scene graph.
  2133.     sv->addAttachedLightManipGeometry();
  2134.     
  2135.     // restore the highting style
  2136.     sv->selection->setHighlightStyle( sv->savedHighlight );
  2137.     
  2138.     // restor the examiner feedback
  2139.     if (sv->whichViewer == SV_VWR_EXAMINER) {
  2140.     SoXtExaminerViewer *exam = (SoXtExaminerViewer *) sv->currentViewer;
  2141.     exam->setFeedbackVisibility( sv->feedbackShown );
  2142.     }
  2143. }
  2144.  
  2145. ////////////////////////////////////////////////////////////////////////
  2146. //
  2147. // Description:
  2148. //    Static routine for processing topbar menu events.
  2149. //  When the menu is created, it stores pointer to the SoSceneViewer
  2150. //  in the client_data, so that we can tell which SoSceneViewer needs
  2151. //  the event.
  2152. //
  2153. // Use: private, static
  2154. //
  2155. void
  2156. SoSceneViewer::processTopbarEvent(
  2157.     Widget,                // Which widget?  I don't care
  2158.     SoSceneViewerData *data,    // Pointer to button/SoSceneViewer
  2159.     XmAnyCallbackStruct *cb )    // X garbage
  2160. //
  2161. ////////////////////////////////////////////////////////////////////////
  2162. {
  2163.     SoSceneViewer *sv = data->classPt;
  2164.     Time eventTime = cb->event->xbutton.time;
  2165.     
  2166.     switch (data->id) {
  2167.     
  2168.     //
  2169.     // File
  2170.     //
  2171.     
  2172.     case SV_FILE_ABOUT:
  2173.     sv->showAboutDialog();
  2174.     break;
  2175.     
  2176.     case SV_FILE_NEW:
  2177.     sv->deleteScene();
  2178.     delete sv->fileName;
  2179.     sv->fileName = NULL;
  2180.     break;
  2181.     
  2182.     case SV_FILE_OPEN:
  2183.     case SV_FILE_IMPORT:
  2184.     case SV_FILE_SAVE_AS:
  2185.     case SV_FILE_READ_ENV:
  2186.     case SV_FILE_SAVE_ENV:
  2187.     sv->fileMode = data->id;
  2188.     sv->getFileName();
  2189.     break;
  2190.     
  2191.     case SV_FILE_SAVE:
  2192.     sv->save();
  2193.     break;
  2194.     
  2195.     case SV_FILE_PRINT:
  2196.         sv->print();
  2197.     break;
  2198.     case SV_FILE_QUIT:
  2199.     delete sv;
  2200.     exit(0);
  2201.     break;
  2202.     
  2203.     //
  2204.     // Edit
  2205.     //
  2206.     
  2207.     case SV_EDIT_PICK_PARENT:
  2208.     sv->pickParent();
  2209.     break;
  2210.     case SV_EDIT_PICK_ALL:
  2211.     sv->pickAll();
  2212.     break;
  2213.     case SV_EDIT_CUT:
  2214.     sv->clipboard->copy((SoPathList *)sv->selection->getList(), eventTime);
  2215.     sv->selection->destroy();
  2216.     sv->updateCommandAvailability();
  2217.     break;
  2218.     case SV_EDIT_COPY:
  2219.     sv->clipboard->copy((SoPathList *)sv->selection->getList(),  eventTime);
  2220.     break;
  2221.     case SV_EDIT_PASTE:
  2222.     sv->clipboard->paste(eventTime, pasteDoneCB, sv);
  2223.     break;
  2224.     case SV_EDIT_DELETE:
  2225.     sv->selection->destroy();
  2226.     sv->updateCommandAvailability();
  2227.     break;
  2228.     
  2229.     //
  2230.     // Viewing
  2231.     //
  2232.     
  2233.     case SV_VIEW_PICK:
  2234.     sv->setViewing(! sv->isViewing());
  2235.         if(! sv->isViewing())
  2236.           {
  2237. #ifdef MYDEBUG
  2238.             printf("TIMER OFF, from pick menu\n");
  2239. #endif
  2240.             timersensor->unschedule();
  2241.             timerflag=0;
  2242.           }
  2243.         else
  2244.           {
  2245. #ifdef MYDEBUG
  2246.             printf("TIMER ON, from pick menu\n");
  2247. #endif
  2248.             timersensor->schedule(SbTime((unsigned long)DATATIME));
  2249.             timerflag=1;
  2250.  
  2251.           }
  2252.     break;
  2253. #ifdef EXPLORER
  2254.     case SV_VIEW_USER:
  2255.     sv->userModeFlag = !sv->userModeFlag;
  2256.     if (sv->userModeFlag)
  2257.         sv->currentViewer->setEventCallback(sv->userModeCB, sv->userModedata);
  2258.     else
  2259.         sv->currentViewer->setEventCallback(NULL, NULL);
  2260.     break;
  2261. #endif
  2262.     
  2263.     case SV_VIEW_EXAMINER:
  2264.     sv->switchToViewer(SV_VWR_EXAMINER);
  2265.     break;
  2266.     case SV_VIEW_WALK:
  2267.     sv->switchToViewer(SV_VWR_WALK);
  2268.     break;
  2269.     case SV_VIEW_PLANE:
  2270.     sv->switchToViewer(SV_VWR_PLANE);
  2271.     break;
  2272.     case SV_VIEW_FLY:
  2273.     sv->switchToViewer(SV_VWR_FLY);
  2274.     break;
  2275.     
  2276.     case SV_VIEW_SELECTION:
  2277.         sv->viewSelection();
  2278.         break;
  2279.  
  2280.     case SV_VIEW_SCREEN_TRANSPARENCY:
  2281.     sv->setTransparencyType(SoGLRenderAction::SCREEN_DOOR);
  2282.     break;
  2283.     case SV_VIEW_BLEND_TRANSPARENCY:
  2284.     sv->setTransparencyType(SoGLRenderAction::BLEND);
  2285.     break;
  2286.     case SV_VIEW_DELAY_BLEND_TRANSPARENCY:
  2287.     sv->setTransparencyType(SoGLRenderAction::DELAYED_BLEND);
  2288.     break;
  2289.     case SV_VIEW_SORT_BLEND_TRANSPARENCY:
  2290.     sv->setTransparencyType(SoGLRenderAction::SORTED_OBJECT_BLEND);
  2291.     break;
  2292.  
  2293.     case SV_VIEW_FOG:
  2294.         sv->setFog(! sv->fogFlag);
  2295.         break;
  2296.     case SV_VIEW_ANTIALIASING:
  2297.         sv->setAntialiasing(! sv->antialiasingFlag);
  2298.         break;
  2299.     case SV_VIEW_BKG_COLOR:
  2300.         sv->editBackgroundColor();
  2301.         break;
  2302.  
  2303.  
  2304.     //
  2305.     // Editors
  2306.     //
  2307.     case SV_EDITOR_MATERIAL:
  2308.     sv->createMaterialEditor();
  2309.     break;
  2310.  
  2311.     case SV_EDITOR_TRANSFORM:
  2312.     sv->createTransformSliderSet();
  2313.     break;
  2314.  
  2315.     case SV_EDITOR_COLOR:
  2316.     sv->createColorEditor();
  2317.     break;
  2318.  
  2319.     //
  2320.     // Selection
  2321.     //
  2322.     case SV_SEL_SINGLE_SELECT:
  2323.         sv->selection->setSelectionPolicy(SoSelection::SINGLE);
  2324.     break;
  2325.  
  2326.     case SV_SEL_TOGGLE_SELECT:
  2327.         sv->selection->setSelectionPolicy(SoSelection::TOGGLE);
  2328.     break;
  2329.  
  2330.     case SV_SEL_SHIFT_SELECT:
  2331.         sv->selection->setSelectionPolicy(SoSelection::SHIFT);
  2332.     break;
  2333.  
  2334.     case SV_SEL_LINE_HIGHLIGHT:
  2335.         sv->selection->setHighlightStyle(sv->lineHighlight);
  2336.     break;
  2337.     case SV_SEL_BBOX_HIGHLIGHT:
  2338.         sv->selection->setHighlightStyle(sv->boxHighlight);
  2339.     break;
  2340.     case SV_SEL_NO_HIGHLIGHT:
  2341.         sv->selection->setHighlightStyle(NULL);
  2342.         break;
  2343.     
  2344.     case SV_SEL_HIGHLIGHT_COLOR:
  2345.         sv->editHighlightColor();
  2346.         break;
  2347.  
  2348.     //
  2349.     // Manips
  2350.     //
  2351.     case SV_MANIP_TRACKBALL:
  2352.     sv->curManip = (sv->curManip == SV_TRACKBALL) ? SV_NONE : SV_TRACKBALL;
  2353.     if ( sv->curManipReplaces )
  2354.         sv->replaceAllManips( sv->curManip );
  2355.         break;
  2356.  
  2357.     case SV_MANIP_HANDLEBOX:
  2358.     sv->curManip = (sv->curManip == SV_HANDLEBOX) ? SV_NONE : SV_HANDLEBOX;
  2359.     if ( sv->curManipReplaces )
  2360.         sv->replaceAllManips( sv->curManip );
  2361.         break;
  2362.  
  2363.     case SV_MANIP_JACK:
  2364.     sv->curManip = (sv->curManip == SV_JACK) ? SV_NONE : SV_JACK;
  2365.     if ( sv->curManipReplaces )
  2366.         sv->replaceAllManips( sv->curManip );
  2367.         break;
  2368.  
  2369.     case SV_MANIP_XFBOX:
  2370.     sv->curManip = (sv->curManip == SV_XFBOX) ? SV_NONE : SV_XFBOX;
  2371.     if ( sv->curManipReplaces )
  2372.         sv->replaceAllManips( sv->curManip );
  2373.         break;
  2374.  
  2375.     case SV_MANIP_DRAGPOINT:
  2376.     sv->curManip = (sv->curManip == SV_DRAGPOINT) ? SV_NONE : SV_DRAGPOINT;
  2377.     if ( sv->curManipReplaces )
  2378.         sv->replaceAllManips( sv->curManip );
  2379.         break;
  2380.  
  2381.     case SV_MANIP_NONE:
  2382.     sv->curManip = SV_NONE;
  2383.     if ( sv->curManipReplaces )
  2384.         sv->detachManipFromAll();
  2385.         break;
  2386.     case SV_MANIP_REPLACE_ALL:
  2387.     // Toggle the value of 'curManipReplaces'
  2388.     sv->curManipReplaces = ( sv->curManipReplaces == TRUE) ? FALSE : TRUE;
  2389.  
  2390.     if ( sv->curManipReplaces )
  2391.         sv->replaceAllManips( sv->curManip );
  2392.         break;
  2393.     
  2394.     //
  2395.     // Lights
  2396.     //
  2397.     case SV_LIGHT_AMBIENT_EDIT:    sv->editAmbientColor(); break;
  2398.     case SV_LIGHT_ADD_DIRECT:    sv->addLight(new SoDirectionalLight); break;
  2399.     case SV_LIGHT_ADD_POINT:    sv->addLight(new SoPointLight); break;
  2400.     case SV_LIGHT_ADD_SPOT:    sv->addLight(new SoSpotLight); break;
  2401.     
  2402.     case SV_LIGHT_TURN_ON:
  2403.     case SV_LIGHT_TURN_OFF:
  2404.     {
  2405.     SbBool onFlag = (data->id == SV_LIGHT_TURN_ON);
  2406.     for (int i=0; i < sv->lightDataList.length(); i++)
  2407.         sv->turnLightOnOff((SvLightData *) sv->lightDataList[i], onFlag);
  2408.     sv->turnLightOnOff( sv->headlightData, onFlag);
  2409.     }
  2410.     break;
  2411.     case SV_LIGHT_SHOW_ALL:
  2412.     case SV_LIGHT_HIDE_ALL:
  2413.     {
  2414.     SbBool onFlag = (data->id == SV_LIGHT_SHOW_ALL);
  2415.     for (int i=0; i < sv->lightDataList.length(); i++)
  2416.         sv->editLight((SvLightData *) sv->lightDataList[i], onFlag);
  2417.     }
  2418.     break;
  2419.     
  2420.     } // endswitch( topbar button )
  2421. }
  2422.  
  2423. ////////////////////////////////////////////////////////////////////////
  2424. //
  2425. // Description:
  2426. //    Adds the given light to the scene and to the menu.
  2427. //
  2428. // Use: private
  2429. //
  2430. void
  2431. SoSceneViewer::addLight(SoLight *light)
  2432. //
  2433. ////////////////////////////////////////////////////////////////////////
  2434. {
  2435.     // create the switch and light node and add it to the scene
  2436.     SoSwitch *lightSwitch = new SoSwitch;
  2437.     lightGroup->addChild(lightSwitch);
  2438.     lightSwitch->addChild(light);
  2439.     SWITCH_LIGHT_ON(lightSwitch);
  2440.     
  2441.     // add the light entry for the new light
  2442.     SvLightData *data = addLightEntry(light, lightSwitch);
  2443.     
  2444.     //
  2445.     // Try to come up with some meaningfull default position base
  2446.     // of the current camera view volume.
  2447.     //
  2448.     SbViewVolume vv;
  2449.     camera->getViewVolume(vv);
  2450.     SbVec3f forward = - vv.zVector();
  2451.     SbVec3f center = camera->position.getValue() + forward * 
  2452.     (camera->nearDistance.getValue() + camera->farDistance.getValue()) / 2.0;
  2453.     SbVec3f position( vv.ulf + forward * vv.nearToFar * .25 );
  2454.     
  2455.     if (data->type == SoLight::DIRECTIONAL) {
  2456.     SoDirectionalLight *light = (SoDirectionalLight *) data->light;
  2457.     // the position of the light will be given to the manip
  2458.     // since the light doesn't have any position field
  2459.     // Don't change the direction for now. If we change the direction,
  2460.     // then the placement of the manipulator during editLight() will be
  2461.     // screwy. This is because the translation given there is relative
  2462.     // to the rotated space that the manipulator is in after it is 
  2463.     // rotated to line up with the light's direction.
  2464.         // light->direction = center - position;
  2465.     }
  2466.     else if (data->type == SoLight::POINT) {
  2467.     SoPointLight *light = (SoPointLight *) data->light;
  2468.     light->location = position;
  2469.     // no direction for this light
  2470.     }
  2471.     else if (data->type == SoLight::SPOT) {
  2472.     SoSpotLight *light = (SoSpotLight *) data->light;
  2473.     light->location = position;
  2474.     light->direction = center - position;
  2475.     }
  2476. }
  2477.  
  2478. ////////////////////////////////////////////////////////////////////////
  2479. //
  2480. // Description:
  2481. //    Creates and append the light data struct, and adds a menu entry
  2482. //  for the light.
  2483. //
  2484. // Use: private
  2485. //
  2486. SvLightData *
  2487. SoSceneViewer::addLightEntry(SoLight *light, SoSwitch *lightSwitch)
  2488. //
  2489. ////////////////////////////////////////////////////////////////////////
  2490. {
  2491.     //
  2492.     // create the light data
  2493.     //
  2494.     
  2495.     SvLightData *data = new SvLightData;
  2496.     lightDataList.append(data);
  2497.     data->light = light;
  2498.     data->lightSwitch = lightSwitch;
  2499.     data->classPt = this;
  2500.     data->colorEditor = NULL;
  2501.     data->manip = NULL;
  2502.     if (light->isOfType(SoDirectionalLight::getClassTypeId()))
  2503.     data->type = SoLight::DIRECTIONAL;
  2504.     else if (light->isOfType(SoPointLight::getClassTypeId()))
  2505.     data->type = SoLight::POINT;
  2506.     else if (light->isOfType(SoSpotLight::getClassTypeId()))
  2507.     data->type = SoLight::SPOT;
  2508.     else
  2509.     fprintf(stderr, "Wrong light type!!\n");
  2510.     
  2511.     // set the correct label name
  2512.     char *str;
  2513.     switch (data->type) {
  2514.     case SoLight::DIRECTIONAL: str = "Directional "; break;
  2515.     case SoLight::POINT: str = "Point "; break;
  2516.     case SoLight::SPOT: str = "Spot "; break;
  2517.     }
  2518.     data->name = strdup(str);
  2519.     
  2520.     //
  2521.     // by default attach the light manipulator to show the light
  2522.     //
  2523.     editLight(data, TRUE);
  2524.     
  2525.     //
  2526.     // add the menu entry
  2527.     //
  2528.     addLightMenuEntry(data);
  2529.     
  2530.     return data;
  2531. }
  2532.  
  2533. ////////////////////////////////////////////////////////////////////////
  2534. //
  2535. // Description:
  2536. //    build the light menu entry for the given light.
  2537. //
  2538. // Use: private
  2539. //
  2540. void
  2541. SoSceneViewer::addLightMenuEntry(SvLightData *data)
  2542. //
  2543. ////////////////////////////////////////////////////////////////////////
  2544. {
  2545.     //
  2546.     // create the motif menu entry
  2547.     //
  2548.     Arg     args[1];
  2549.     
  2550.     Widget menu = menuItems[SV_LIGHT].widget;
  2551.     
  2552.     // makes sure menu has been built
  2553.     if (menu == NULL)
  2554.     return;
  2555.     
  2556.     // create the submenu widget, adding a callback to update the toggles
  2557.     data->submenuWidget = XmCreatePulldownMenu(menu, NULL, NULL, 0);
  2558.     XtAddCallback(data->submenuWidget, XmNmapCallback,
  2559.     (XtCallbackProc) SoSceneViewer::lightSubmenuDisplay,
  2560.     (XtPointer) data);
  2561.     
  2562.     // create a cascade menu entry which will bring the submenu
  2563.     XtSetArg(args[0], XmNsubMenuId, data->submenuWidget);
  2564.     data->cascadeWidget = XtCreateWidget(data->name, 
  2565.     xmCascadeButtonGadgetClass, menu, args, 1);
  2566.     
  2567.     // add "on/off" toggle
  2568.     data->onOffWidget = XtCreateWidget("On/Off", xmToggleButtonGadgetClass, 
  2569.     data->submenuWidget, NULL, 0);
  2570.     XtAddCallback(data->onOffWidget, XmNvalueChangedCallback,
  2571.     (XtCallbackProc) SoSceneViewer::lightToggleCB, (XtPointer) data);
  2572.     
  2573.     // add "Icon" toggle
  2574.     data->iconWidget = XtCreateWidget("Icon", xmToggleButtonGadgetClass, 
  2575.     data->submenuWidget, NULL, 0);
  2576.     XtAddCallback(data->iconWidget, XmNvalueChangedCallback,
  2577.     (XtCallbackProc) SoSceneViewer::editLightToggleCB, (XtPointer) data);
  2578.     
  2579.     // add "Edit Color" toggle
  2580.     data->editColorWidget = XtCreateWidget("Edit Color", xmPushButtonGadgetClass, 
  2581.     data->submenuWidget, NULL, 0);
  2582.     XtAddCallback(data->editColorWidget, XmNactivateCallback,
  2583.     (XtCallbackProc) SoSceneViewer::editLightColorCB, (XtPointer) data);
  2584.     
  2585.     // add "Remove" entry
  2586.     data->removeWidget = XtCreateWidget("Remove", xmPushButtonGadgetClass, 
  2587.     data->submenuWidget, NULL, 0);
  2588.     XtAddCallback(data->removeWidget, XmNactivateCallback,
  2589.     (XtCallbackProc) SoSceneViewer::removeLightCB, (XtPointer) data);
  2590.     
  2591.     // manage children
  2592.     XtManageChild(data->onOffWidget);
  2593.     XtManageChild(data->iconWidget);
  2594.     XtManageChild(data->editColorWidget);
  2595.     XtManageChild(data->removeWidget);
  2596.     XtManageChild(data->cascadeWidget);
  2597. }
  2598.  
  2599. ////////////////////////////////////////////////////////////////////////
  2600. //
  2601. // Description:
  2602. //    Called by "On/Off" light menu entry when toggle changes.
  2603. //
  2604. // Use: static private
  2605. //
  2606. void
  2607. SoSceneViewer::lightToggleCB(Widget toggle, SvLightData *data, void *)
  2608. //
  2609. ////////////////////////////////////////////////////////////////////////
  2610. {
  2611.     data->classPt->turnLightOnOff(data, XmToggleButtonGetState(toggle));
  2612. }
  2613.  
  2614. ////////////////////////////////////////////////////////////////////////
  2615. //
  2616. // Description:
  2617. //    Turn the given light on or off.
  2618. //
  2619. // Use: private
  2620. //
  2621. void
  2622. SoSceneViewer::turnLightOnOff(SvLightData *data, SbBool flag)
  2623. //
  2624. ////////////////////////////////////////////////////////////////////////
  2625. {
  2626.     // check if it is the headlight
  2627.     if (data == headlightData)
  2628.     setHeadlight( flag );
  2629.     else {
  2630.     if ( flag )
  2631.         SWITCH_LIGHT_ON(data->lightSwitch);
  2632.     else
  2633.         SWITCH_LIGHT_OFF(data->lightSwitch);
  2634.     }
  2635. }
  2636.  
  2637. ////////////////////////////////////////////////////////////////////////
  2638. //
  2639. // Description:
  2640. //    "Edit" light menu entry callback.
  2641. //
  2642. // Use: static private
  2643. //
  2644. void
  2645. SoSceneViewer::editLightToggleCB(Widget toggle, SvLightData *data, void *)
  2646. //
  2647. ////////////////////////////////////////////////////////////////////////
  2648. {
  2649.     data->classPt->editLight( data, XmToggleButtonGetState(toggle) );
  2650. }
  2651.  
  2652. ////////////////////////////////////////////////////////////////////////
  2653. //
  2654. // Description:
  2655. //    Attach/detach the correct manipulator on the given light.
  2656. //
  2657. // Use: private
  2658. //
  2659. void
  2660. SoSceneViewer::editLight(SvLightData *data, SbBool flag)
  2661. //
  2662. ////////////////////////////////////////////////////////////////////////
  2663. {
  2664.     // ??? check if this is for the headlight, which is special cased
  2665.     // ??? since a manipulator cannot be used (aligned to camera).
  2666.     SbBool forHeadlight = (data == data->classPt->headlightData);
  2667.     
  2668.     //
  2669.     // attach the manip to the light and add it to the scene
  2670.     //
  2671.     if (flag) {
  2672.     
  2673.     // allocate the right manipulator type if needed
  2674.     if (!forHeadlight && data->manip == NULL) {
  2675.         switch (data->type) {
  2676.         case SoLight::DIRECTIONAL:
  2677.             {
  2678.             data->manip = new SoDirectionalLightManip;
  2679.             
  2680.             // make the manip come at some meaningfull position based
  2681.             // on the current camera view volume. This position should 
  2682.             // match whatever is done when the other lights are created.
  2683.             SbViewVolume vv;
  2684.             camera->getViewVolume(vv);
  2685.             SbVec3f forward = - vv.zVector();
  2686.             SbVec3f position( vv.ulf + forward * vv.nearToFar * .25 );
  2687.             SoTransform *xfm = data->manip->getWorkSpaceOffset();
  2688.             xfm->translation = position;
  2689.             }
  2690.             break;
  2691.         case SoLight::POINT:
  2692.             data->manip = new SoPointLightManip;
  2693.             break;
  2694.         case SoLight::SPOT:
  2695.             data->manip = new SoSpotLightManip;
  2696.             break;
  2697.         }
  2698.         data->manip->ref();
  2699.     }
  2700.     else if (forHeadlight && headlightEditor == NULL) {
  2701.         headlightEditor = new SoXtDirectionalLightEditor;
  2702.         headlightEditor->setTitle("Headlight Editor");
  2703.     }
  2704.     
  2705.     // if this is for the headlight, make sure we have the
  2706.     // current viewer headlight
  2707.     if (forHeadlight)
  2708.         data->light = data->classPt->getHeadlight();
  2709.     
  2710.     // get the path from the root to the light node
  2711.     SoSearchAction sa;
  2712.     sa.setNode( data->light );
  2713.     sa.apply( currentViewer->getSceneGraph() );
  2714.     SoPath *path = sa.getPath();
  2715.     // ??? light is probably turned off so we don't 
  2716.     // ??? need to print a warning message. Just don't
  2717.     // ??? do anything
  2718.     if (path == NULL)
  2719.         return;
  2720.     
  2721.     if (forHeadlight) {
  2722.         // attach the dir light editor
  2723.         // ??? don't use the path from the root to the headlight 
  2724.         // ??? since we want the light to be relative to the 
  2725.         // ??? camera (i.e. moving the camera shouldn't affect
  2726.         // ??? the arrow in the editor since that direction
  2727.         // ??? is relative to the camera).
  2728.         SoPath *littlePath = new SoPath( data->light );
  2729.         headlightEditor->attach( littlePath );
  2730.         headlightEditor->show();
  2731.     }
  2732.     else {
  2733.         // attach manip and insert it in the scene
  2734.         data->manip->attach( path );
  2735.  
  2736.         // After attaching, we set the workspace and edit paths to
  2737.         // be just single node paths containing the light.
  2738.         // We want to do this so that changing the camera and the
  2739.         // headlight rotation will not cause notification triggers on the
  2740.         // edit and work space paths. This will make it more efficient.
  2741.         // We can do this ONLY because we know the structure of our
  2742.         // scene graph. The scene graph is designed so that no transforms
  2743.         // affect the light (i.e., no transforms that affect the light 
  2744.         // appear between traversing the camera and traversing the light).
  2745.         // We can't just attach to this littlePath in the first place,
  2746.         // because the "attach()" method creates a default size for 
  2747.         // light manipulators based on the size of the
  2748.         // scene given by the path handed to attach().
  2749.  
  2750.         // So we attach to the full path, which establishes a nice size,
  2751.         // and then we set the other two paths to be more efficient.
  2752.         SoPath *littlePath = new SoPath( data->light );
  2753.         data->manip->setWorkSpacePath( littlePath );
  2754.         data->manip->setEditPath( littlePath );
  2755.         
  2756.         // add the manip to the scene graph
  2757.         if (selection->findChild(data->manip) < 0)
  2758.         selection->addChild( data->manip );
  2759.         
  2760.         // now that the light manip has been attached, make sure
  2761.         // that they all have consistent sizes (they come up to be
  2762.         // a percentage of the scene size, which will change over
  2763.         // time, so light 1 and light 2 will not otherwise have the 
  2764.         // same size).
  2765.         if ( calculatedLightManipSize )
  2766.         data->manip->setSizingBox( lightManipSize );
  2767.         else {
  2768.         // get the size of the first light manip. Others will
  2769.         // use that size....
  2770.         lightManipSize = data->manip->getSizingBox();
  2771.         calculatedLightManipSize = TRUE;
  2772.         }
  2773.     }
  2774.     }
  2775.     //
  2776.     // detach the manip from the light and remove it from the scene
  2777.     //
  2778.     else {
  2779.     if (forHeadlight) {
  2780.         // detach editor from light
  2781.         if (headlightEditor != NULL) {
  2782.         headlightEditor->detach();
  2783.         headlightEditor->hide();
  2784.         }
  2785.     }
  2786.     else {
  2787.         // detach manip from light
  2788.         if (data->manip != NULL) {
  2789.         data->manip->detach();
  2790.         selection->removeChild( data->manip );
  2791.         }
  2792.     }
  2793.     }
  2794. }
  2795.  
  2796. ////////////////////////////////////////////////////////////////////////
  2797. //
  2798. // Description:
  2799. //    Called by "Edit Color" light menu entry.
  2800. //
  2801. // Use: static private
  2802. //
  2803. void
  2804. SoSceneViewer::editLightColorCB(Widget, SvLightData *data, void *)
  2805. //
  2806. ////////////////////////////////////////////////////////////////////////
  2807. {
  2808.     // create the color editor with the right title
  2809.     if (data->colorEditor == NULL) {
  2810.     data->colorEditor = new SoXtColorEditor;
  2811.     char str[50];
  2812.     strcpy(str, data->name);
  2813.     strcat(str, " Light Color");
  2814.     data->colorEditor->setTitle(str);
  2815.     }
  2816.     
  2817.     if ( !data->colorEditor->isAttached() ) {
  2818.     // if this is for the headlight, make sure we have the
  2819.     // current viewer headlight
  2820.     if (data == data->classPt->headlightData)
  2821.         data->light = data->classPt->getHeadlight();
  2822.     
  2823.     // normalize the light intensity
  2824.     SbColor col;
  2825.     col = data->light->color.getValue();
  2826.     col *= data->light->intensity.getValue();
  2827.     data->light->intensity.setValue( 1.0 );
  2828.     data->light->color.setValue( col );
  2829.     
  2830.     data->colorEditor->attach( &data->light->color, data->light );
  2831.     }
  2832.     
  2833.     data->colorEditor->show();
  2834. }
  2835.  
  2836. ////////////////////////////////////////////////////////////////////////
  2837. //
  2838. // Description:
  2839. //    remove button menu entry callback.
  2840. //
  2841. // Use: static private
  2842. //
  2843. void
  2844. SoSceneViewer::removeLightCB(Widget, SvLightData *data, void *)
  2845. //
  2846. ////////////////////////////////////////////////////////////////////////
  2847. {
  2848.     data->classPt->removeLight(data);
  2849. }
  2850.  
  2851. ////////////////////////////////////////////////////////////////////////
  2852. //
  2853. // Description:
  2854. //    removes the light from the scene, and removes the light data 
  2855. //  and pulldown menu entry.
  2856. //
  2857. // Use: private
  2858. //
  2859. void
  2860. SoSceneViewer::removeLight(SvLightData *data)
  2861. //
  2862. ////////////////////////////////////////////////////////////////////////
  2863. {
  2864.     // delete the color editor and manip
  2865.     delete data->colorEditor;
  2866.     if (data->manip != NULL) {
  2867.     data->manip->detach();
  2868.     int index = selection->findChild(data->manip);
  2869.     if (index > 0)
  2870.         selection->removeChild(index);
  2871.     data->manip->unref();
  2872.     }
  2873.     
  2874.     // remove the light from the scene
  2875.     lightGroup->removeChild( data->lightSwitch );
  2876.     
  2877.     // nuke the menu entry
  2878.     if (data->cascadeWidget != NULL)
  2879.     XtDestroyWidget( data->cascadeWidget );
  2880.     
  2881.     // remove from list and delete the struct
  2882.     lightDataList.remove( lightDataList.find(data) );
  2883.     delete data;
  2884. }
  2885.  
  2886. ////////////////////////////////////////////////////////////////////////
  2887. //
  2888. // Description:
  2889. //    Called whenever a light submenu is mapped on screen (update 
  2890. //  the toggles)
  2891. //
  2892. // Use: static private
  2893. //
  2894. void
  2895. SoSceneViewer::lightSubmenuDisplay(Widget, SvLightData *data, void *)
  2896. //
  2897. ////////////////////////////////////////////////////////////////////////
  2898. {
  2899.     SoSceneViewer *sv = data->classPt;
  2900.     SbBool set;
  2901.     
  2902.     //
  2903.     // update the "on/off" toggle
  2904.     //
  2905.     if (data == sv->headlightData)
  2906.     set = sv->isHeadlight();
  2907.     else
  2908.     set = IS_LIGHT_ON(data->lightSwitch);
  2909.     if (set)
  2910.     TOGGLE_ON(data->onOffWidget);
  2911.     else
  2912.     TOGGLE_OFF(data->onOffWidget);
  2913.     
  2914.     //
  2915.     // update the "Edit" toggle
  2916.     //
  2917.     if (data == sv->headlightData)
  2918.     set = (sv->headlightEditor != NULL && sv->headlightEditor->isVisible());
  2919.     else
  2920.     set = (data->manip != NULL && data->manip->isAttached());
  2921.     if (set)
  2922.     TOGGLE_ON(data->iconWidget);
  2923.     else
  2924.     TOGGLE_OFF(data->iconWidget);
  2925. }
  2926.  
  2927. ////////////////////////////////////////////////////////////////////////
  2928. //
  2929. // Description:
  2930. //    Called after a paste operation has completed.
  2931. //
  2932. // Use: static, private
  2933. //
  2934. void
  2935. SoSceneViewer::pasteDoneCB(void *userData, SoPathList *pathList)
  2936. //
  2937. ////////////////////////////////////////////////////////////////////////
  2938. {
  2939.     SoSceneViewer *sv = (SoSceneViewer *) userData;
  2940.     sv->pasteDone(pathList);
  2941. }
  2942.  
  2943. ////////////////////////////////////////////////////////////////////////
  2944. //
  2945. // Description:
  2946. //    Called after a paste operation has completed, this adds the
  2947. // pasted data to our scene graph.
  2948. //
  2949. // Use: private
  2950. //
  2951. void
  2952. SoSceneViewer::pasteDone(SoPathList *pathList)
  2953. //
  2954. ////////////////////////////////////////////////////////////////////////
  2955. {
  2956.     if (pathList->length() <= 0)
  2957.         return;
  2958.  
  2959.     // first, detach manips from all selected objects
  2960.     detachManipFromAll();
  2961.     
  2962.     // now, turn off the sel/desel callbacks.
  2963.     // we'll turn them on again after we've adjusted the selection
  2964.     selection->removeObjectSelectedCallback( SoSceneViewer::selectionCallback, this );
  2965.     selection->removeObjectDeselectedCallback( SoSceneViewer::deselectionCallback, this );
  2966.     
  2967.     // now deselect all, and build up a selection from the pasted paths
  2968.     selection->deselectAll();
  2969.     
  2970.     // Add every path in the path list as a child under selection.
  2971.     // Then select each of these paths.
  2972.     for (int i = 0; i < pathList->length(); i++) {
  2973.     
  2974.         // if the head of the path is a selection node, then don't
  2975.     // paste the head - rather, paste all of its children. 
  2976.     // this makes sure we don't have more than 1 selection node.
  2977.     // While we're adding the paths as children, select each path.
  2978.         SoPath *p = (*pathList)[i];
  2979.     SoNode *head = p->getHead();
  2980.     SoPath *selpath;
  2981.     if (head->isOfType(SoSelection::getClassTypeId())) {
  2982.         for (int j = 0; j < ((SoSelection *)head)->getNumChildren(); j++) {
  2983.             selection->addChild(((SoSelection *)head)->getChild(j));
  2984.         
  2985.         // create a path from selection to this child
  2986.         // and select the path.
  2987.         selpath = new SoPath(selection);
  2988.         selpath->append(selection->getNumChildren() - 1);
  2989.         selection->select(selpath);
  2990.         }
  2991.     }
  2992.     else {
  2993.         // not a selection node, so just add it.
  2994.         selection->addChild(p->getHead());
  2995.         
  2996.         // create a path from selection to this child
  2997.         // and select the path.
  2998.         selpath = new SoPath(selection);
  2999.         selpath->append(selection->getNumChildren() - 1);
  3000.         selection->select(selpath);
  3001.     }
  3002.     }
  3003.     
  3004.     // now add manips to all the selected objects
  3005.     attachManipToAll(curManip);
  3006.     
  3007.     // and turn the sel/desel callbacks back on
  3008.     selection->addObjectSelectedCallback( SoSceneViewer::selectionCallback, this );
  3009.     selection->addObjectDeselectedCallback( SoSceneViewer::deselectionCallback, this );
  3010.     
  3011.     // enable/disable keyboard shortcuts
  3012.     updateCommandAvailability();
  3013.  
  3014.     delete pathList;
  3015. }
  3016.  
  3017. ////////////////////////////////////////////////////////////////////////
  3018. //
  3019. // Description:
  3020. //    Build routine for SceneViewer.  This creates all of the X widgets
  3021. //
  3022. // Use: public, virtual
  3023.  
  3024. Widget
  3025. SoSceneViewer::buildWidget(Widget parent, const char *name)
  3026. //
  3027. ////////////////////////////////////////////////////////////////////////
  3028. {
  3029.     int        n;
  3030.     Arg        args[10];
  3031.     
  3032.     // create a form to hold everything together
  3033.     SbVec2s size = getSize();
  3034.     n = 0;
  3035.     if (size[0] != 0 && size[1] != 0) {
  3036.     XtSetArg(args[n], XtNwidth, size[0]); n++;
  3037.     XtSetArg(args[n], XtNheight, size[1]); n++;
  3038.     }
  3039.     mgrWidget = XtCreateWidget(name, xmFormWidgetClass, parent, args, n);
  3040.     registerWidget(mgrWidget, "SoSceneViewer");
  3041.     
  3042.     // create the topbar menu
  3043.     if (showMenuFlag)
  3044.     buildAndLayoutMenu(mgrWidget);
  3045.     
  3046.     // build and layout the current viewer
  3047.     buildAndLayoutViewer(currentViewer);
  3048.     
  3049.     // manage those children
  3050.     if (showMenuFlag)
  3051.     XtManageChild(menuWidget);
  3052.     currentViewer->show();
  3053.     
  3054.     // get the highlight style (line or bbox) from X resources
  3055.     SoXtResource xr(mgrWidget);
  3056.     char *style;
  3057.     if (xr.getResource("highlightStyle", "HighlightStyle", style)) {
  3058.     if (strcmp(style, "line") == 0)
  3059.         selection->setHighlightStyle(lineHighlight);
  3060.     else if (strcmp(style, "box") == 0)
  3061.         selection->setHighlightStyle(boxHighlight);
  3062.     }
  3063.     
  3064.     // clipboard is for copy/paste of 3d data.
  3065.     //??? what if this SceneViewer had its widget destroyed and rebuilt?
  3066.     //??? we need to destroy the clipboards when that happens.
  3067.     clipboard = new SoXtClipboard(mgrWidget);
  3068.     
  3069.     return mgrWidget;
  3070. }
  3071.  
  3072. ////////////////////////////////////////////////////////////////////////
  3073. //
  3074. // Description:
  3075. //    Builds and layout the given viewer.
  3076. //
  3077. // Use: private
  3078. void
  3079. SoSceneViewer::buildAndLayoutViewer(SoXtFullViewer *vwr)
  3080. //
  3081. ////////////////////////////////////////////////////////////////////////
  3082. {
  3083.     if (mgrWidget == NULL)
  3084.     return;
  3085.     
  3086.     // build the viewer if necessary
  3087.     if (vwr->getWidget() == NULL)
  3088.     vwr->build(mgrWidget);
  3089.     
  3090.     // layout the viewer to be attached under the topbar menu
  3091.     // (if the pulldown menu is shown)
  3092.     Arg args[12];
  3093.     int n = 0;
  3094.     if ( showMenuFlag ) {
  3095.     XtSetArg(args[n], XmNtopAttachment,    XmATTACH_WIDGET); n++;
  3096.     XtSetArg(args[n], XmNtopWidget,        menuWidget); n++;
  3097.     }
  3098.     else {
  3099.     XtSetArg(args[n], XmNtopAttachment,    XmATTACH_FORM); n++;
  3100.     }
  3101.     XtSetArg(args[n], XmNbottomAttachment,    XmATTACH_FORM); n++;
  3102.     XtSetArg(args[n], XmNleftAttachment,    XmATTACH_FORM); n++;
  3103.     XtSetArg(args[n], XmNrightAttachment,    XmATTACH_FORM); n++;
  3104.     XtSetValues(vwr->getWidget(), args, n);
  3105. }
  3106.  
  3107. ////////////////////////////////////////////////////////////////////////
  3108. //
  3109. // Description:
  3110. //    Create topbar menu.  Invalid buttons are rendered gray.
  3111. //      Each button's callback include a structure with the ID
  3112. //      of the button and a pointer to the SoSceneViewer that created
  3113. //      it.
  3114. //
  3115. // Use: private
  3116. //
  3117. void
  3118. SoSceneViewer::buildAndLayoutMenu(Widget parent)
  3119. //
  3120. ////////////////////////////////////////////////////////////////////////
  3121. {
  3122.     if (menuWidget != NULL)
  3123.     return;
  3124.     
  3125.     Arg            args[4];
  3126.     int            i, j, n, id;
  3127.     WidgetList        buttons, subButtons;
  3128.     int            itemCount, subItemCount;
  3129.     WidgetClass            widgetClass;
  3130.     String              callbackReason;
  3131.  
  3132.     // create topbar menu
  3133.     menuWidget = XmCreateMenuBar(parent, "menuBar", NULL, 0);
  3134.  
  3135.     itemCount = XtNumber(pulldownData);
  3136.     buttons = (WidgetList) XtMalloc(itemCount * sizeof(Widget));
  3137.  
  3138.     for (i = 0; i < itemCount; i++) {
  3139.     // Make Topbar menu button
  3140.     Widget subMenu = XmCreatePulldownMenu(menuWidget, NULL, NULL, 0);
  3141.     
  3142.     id = pulldownData[i].id;
  3143.     menuItems[id].widget = subMenu;
  3144.         XtAddCallback(subMenu, XmNmapCallback,
  3145.         (XtCallbackProc) SoSceneViewer::menuDisplay,
  3146.         (XtPointer) &menuItems[id]);
  3147.  
  3148.         XtSetArg(args[0], XmNsubMenuId, subMenu);
  3149.     buttons[i] = XtCreateWidget(pulldownData[i].name,
  3150.         xmCascadeButtonGadgetClass, menuWidget, args, 1);
  3151.  
  3152.     // Make subMenu buttons
  3153.     subItemCount = pulldownData[i].subItemCount;
  3154.     subButtons = (WidgetList) XtMalloc(subItemCount * sizeof(Widget));
  3155.     
  3156.     for (j = 0; j < subItemCount; j++) {
  3157.         if (pulldownData[i].subMenu[j].id == SV_SEPARATOR)
  3158.         subButtons[j] = XtCreateWidget(NULL, xmSeparatorGadgetClass, 
  3159.             subMenu, NULL, 0);
  3160.         else {
  3161.                 switch (pulldownData[i].subMenu[j].buttonType) {
  3162.             case SV_PUSH_BUTTON:
  3163.             widgetClass = xmPushButtonGadgetClass;
  3164.             callbackReason = XmNactivateCallback;
  3165.             n = 0;
  3166.                 break;
  3167.             case SV_TOGGLE_BUTTON:
  3168.             widgetClass = xmToggleButtonGadgetClass;
  3169.             callbackReason = XmNvalueChangedCallback;
  3170.             n = 0;
  3171.                 break;
  3172.             case SV_RADIO_BUTTON:
  3173.             widgetClass = xmToggleButtonGadgetClass;
  3174.             callbackReason = XmNvalueChangedCallback;
  3175.             XtSetArg(args[0], XmNindicatorType, XmONE_OF_MANY);
  3176.             n = 1;
  3177.                 break;
  3178.             default:
  3179.             fprintf(stderr, "SceneViewer INTERNAL ERROR: bad buttonType\n");
  3180.                 break;
  3181.         }
  3182.         
  3183.         // check for keyboard accelerator
  3184.         char *accel = pulldownData[i].subMenu[j].accelerator;
  3185.         char *accelText = pulldownData[i].subMenu[j].accelText;
  3186.         if (accel != NULL) {
  3187.             XtSetArg(args[n], XmNaccelerator, accel); n++;
  3188.             
  3189.             if (accelText != NULL) {
  3190.             XmString xmstr = XmStringCreate(accelText,
  3191.                      XmSTRING_DEFAULT_CHARSET);
  3192.             XtSetArg(args[n], XmNacceleratorText, xmstr); n++;
  3193.             //??? can we ever free the xmstr?
  3194.             }
  3195.         }
  3196.         
  3197.         subButtons[j] = XtCreateWidget(
  3198.             pulldownData[i].subMenu[j].name,
  3199.             widgetClass,
  3200.             subMenu, args, n);
  3201.         
  3202.         id = pulldownData[i].subMenu[j].id;
  3203.         menuItems[id].widget = subButtons[j];
  3204.         XtAddCallback(subButtons[j], callbackReason,
  3205.             (XtCallbackProc)SoSceneViewer::processTopbarEvent,
  3206.             (XtPointer) &menuItems[id]);
  3207.         }
  3208.     }
  3209.     XtManageChildren(subButtons, subItemCount);
  3210.     XtFree((char *)subButtons);
  3211.     }
  3212.     XtManageChildren(buttons, itemCount);
  3213.     XtFree((char *)buttons);
  3214.     
  3215.     //
  3216.     // layout the menu bar
  3217.     //
  3218.     n = 0;
  3219.     XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
  3220.     XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
  3221.     XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
  3222.     XtSetValues(menuWidget, args, n);
  3223.     
  3224.     //
  3225.     // If no accumulation buffer, disable antialiasing button.
  3226.     // If no fog support, disable fog button.
  3227.     //
  3228.     if ( getgdesc( GD_BITS_ACBUF_HW ) == 0 ) {
  3229.     XtSetArg(args[0], XmNsensitive, False);
  3230.     XtSetValues(menuItems[SV_VIEW_ANTIALIASING].widget, args, 1);
  3231.     }
  3232.     if ( getgdesc( GD_FOGVERTEX ) == 0 ) {
  3233.     XtSetArg(args[0], XmNsensitive, False);
  3234.     XtSetValues(menuItems[SV_VIEW_FOG].widget, args, 1);
  3235.     }
  3236.     
  3237.     
  3238.     //
  3239.     // Add the light items which are dynamically created
  3240.     //    
  3241.     
  3242.     // first add the headlight
  3243.     addLightMenuEntry(headlightData);
  3244.     XtUnmanageChild(headlightData->removeWidget);
  3245.     XtUnmanageChild(headlightData->editColorWidget);
  3246.     XmString xmstr = XmStringCreate("Edit", XmSTRING_DEFAULT_CHARSET);
  3247.     XtSetArg(args[0], XmNlabelString, xmstr);
  3248.     XtSetValues(headlightData->iconWidget, args, 1);
  3249.     
  3250.     // now the regular lights
  3251.     for (i=0; i < lightDataList.length(); i++)
  3252.     addLightMenuEntry( (SvLightData *) lightDataList[i] );
  3253. }
  3254.  
  3255. ////////////////////////////////////////////////////////////////////////
  3256. //
  3257. // Description:
  3258. //    Show/hide the pulldown menu bar.
  3259. //
  3260. // Use: public
  3261. void
  3262. SoSceneViewer::showMenu(SbBool flag)
  3263. //
  3264. ////////////////////////////////////////////////////////////////////////
  3265. {
  3266.     if (showMenuFlag == flag || mgrWidget == NULL) {
  3267.     showMenuFlag = flag;
  3268.     return;
  3269.     }
  3270.     
  3271.     showMenuFlag = flag;
  3272.     
  3273.     if ( showMenuFlag ) {
  3274.     
  3275.     // turn topbar menu on
  3276.     if (menuWidget == NULL)
  3277.         buildAndLayoutMenu(mgrWidget);
  3278.     XtManageChild(menuWidget);
  3279.         
  3280.     // attach viewer to bottom of menu
  3281.     Arg args[2];
  3282.     int n = 0;
  3283.     XtSetArg(args[n], XmNtopAttachment,    XmATTACH_WIDGET); n++;
  3284.     XtSetArg(args[n], XmNtopWidget,        menuWidget);    n++;
  3285.     XtSetValues(currentViewer->getWidget(), args, n);
  3286.     }
  3287.     else {
  3288.     // attach viewer to form
  3289.     Arg args[2];
  3290.     int n = 0;
  3291.     XtSetArg(args[n], XmNtopAttachment,    XmATTACH_FORM); n++;
  3292.     XtSetValues(currentViewer->getWidget(), args, n);
  3293.         
  3294.     // turn topbar menu off
  3295.     if (menuWidget != NULL)
  3296.         XtUnmanageChild(menuWidget);
  3297.     }
  3298. }
  3299.  
  3300. ////////////////////////////////////////////////////////////////////////
  3301. //
  3302. //  Manage the changes in the selected node(s)
  3303. //
  3304. //  Use: private, static
  3305. //
  3306. void
  3307. SoSceneViewer::deselectionCallback( void *userData,           // my data
  3308.                     SoPath *deselectedObject )     // object
  3309. //
  3310. ////////////////////////////////////////////////////////////////////////
  3311. {
  3312.     SoSceneViewer *sv = (SoSceneViewer *) userData;
  3313.  
  3314.     // remove the manip
  3315.     sv->detachManip( deselectedObject );
  3316.     
  3317.     // Remove editors
  3318.     if (sv->materialEditor)
  3319.     sv->materialEditor->detach();
  3320.     
  3321.     if (sv->colorEditor)
  3322.         sv->colorEditor->detach();
  3323.  
  3324.     if (sv->transformSliderSet)
  3325.     sv->transformSliderSet->setNode( NULL );    // ??? same as detach ??? rc
  3326.  
  3327.     // enable/disable cmd key shortcuts and menu items
  3328.     sv->updateCommandAvailability();
  3329. }
  3330.  
  3331. ////////////////////////////////////////////////////////////////////////
  3332. //
  3333. //  Manage the changes in the selected node(s)
  3334. //
  3335. //  Use: private, static
  3336. //
  3337. void
  3338. SoSceneViewer::selectionCallback( void *userData,        // my data
  3339.                   SoPath *selectedObject )    // object
  3340. //
  3341. ////////////////////////////////////////////////////////////////////////
  3342. {
  3343.     SoSceneViewer *sv = (SoSceneViewer *) userData;
  3344.  
  3345.     // attach the manip
  3346.     sv->attachManip( sv->curManip, selectedObject );
  3347.  
  3348.     //
  3349.     // If active, attach editors to new selection.
  3350.     //
  3351.     SoMaterial *mtl = NULL;
  3352.     if ( sv->materialEditor && (sv->materialEditor->getWidget() != NULL)) {
  3353.     mtl = sv->findMaterialForAttach(selectedObject);
  3354.     sv->materialEditor->attach(mtl);
  3355.     }
  3356.     
  3357.     if (sv->colorEditor && (sv->colorEditor->getWidget() != NULL)) {
  3358.         if (mtl == NULL)
  3359.         mtl = sv->findMaterialForAttach(selectedObject);
  3360.         sv->colorEditor->attach(&(mtl->diffuseColor), 0, mtl);
  3361.     }
  3362.     
  3363.     if ( sv->transformSliderSet && sv->transformSliderSet->getWidget() ) {
  3364.     SoPath      *editTransformPath;
  3365.     editTransformPath = sv->findTransformForAttach( selectedObject );
  3366.     if ( editTransformPath == NULL ) {
  3367.         sv->transformSliderSet->setNode( NULL );
  3368.     }
  3369.     else  {
  3370.         sv->transformSliderSet->setNode( editTransformPath->getTail() );
  3371.     }
  3372.     }
  3373.  
  3374.     // enable/disable cmd key shortcuts and menu items
  3375.     sv->updateCommandAvailability();
  3376. }
  3377.     
  3378. ////////////////////////////////////////////////////////////////////////
  3379. //
  3380. //  Change the highlight color by putting up a color editor.
  3381. //
  3382. //  Use: private
  3383. //
  3384. void
  3385. SoSceneViewer::editHighlightColor()
  3386. //
  3387. ////////////////////////////////////////////////////////////////////////
  3388. {
  3389.     if (highlightColorEditor == NULL) {
  3390.         highlightColorEditor = new SoXtColorEditor;
  3391.     highlightColorEditor->setTitle("Highlight Color");
  3392.     highlightColorEditor->addColorChangedCallback(
  3393.         SoSceneViewer::highlightColorCallback, this);
  3394.     }
  3395.     highlightColorEditor->build();
  3396.     
  3397.     // set the color. our highlights are all the same color, so just pick one.
  3398.     // (although, if the user set different colors in their X defaults...)
  3399.     ignoreCallback = TRUE;
  3400.     if (selection->getHighlightStyle() == lineHighlight)
  3401.         highlightColorEditor->setColor(lineHighlight->getColor());
  3402.     else
  3403.         highlightColorEditor->setColor(boxHighlight->getColor());
  3404.     ignoreCallback = FALSE;
  3405.     
  3406.     // show that color editor!
  3407.     highlightColorEditor->show();
  3408. }
  3409.  
  3410. ////////////////////////////////////////////////////////////////////////
  3411. //
  3412. //  Callback proc invoked by the color editor, this changes the
  3413. //  highlight color for selected objects.
  3414. //
  3415. //  Use: static, private
  3416. //
  3417. void
  3418. SoSceneViewer::highlightColorCallback(void *userData, const SbColor *c)
  3419. //
  3420. ////////////////////////////////////////////////////////////////////////
  3421. {
  3422.     SoSceneViewer *sv = (SoSceneViewer *) userData;
  3423.     
  3424.     if (sv->ignoreCallback)
  3425.         return;
  3426.     
  3427.     // change highlight color for line and box highlight styles.
  3428.     sv->boxHighlight->setColor(*c);
  3429.     sv->lineHighlight->setColor(*c);
  3430. }
  3431.  
  3432. ////////////////////////////////////////////////////////////////////////
  3433. //
  3434. //  This enables/disables cmd key shortcuts and menu items
  3435. //  based on whether there are any objects, and/or any selected objects
  3436. //  in the scene graph.
  3437. //
  3438. //  Use: static private
  3439. //
  3440. // 
  3441. void
  3442. SoSceneViewer::updateCommandAvailability()
  3443. //
  3444. ////////////////////////////////////////////////////////////////////////
  3445. {
  3446.     Arg args[1];
  3447.  
  3448.     // enable/disable based on the number of child objects in scene
  3449.     if (selection->getNumChildren() == 0)
  3450.      XtSetArg(args[0], XmNsensitive, False);
  3451.     else XtSetArg(args[0], XmNsensitive, True);
  3452.     
  3453.     // save (if no children, nothing to save)
  3454.     XtSetValues(menuItems[SV_FILE_SAVE].widget, args, 1);
  3455.     XtSetValues(menuItems[SV_FILE_SAVE_AS].widget, args, 1);
  3456.     
  3457. #ifndef EXPLORER
  3458.     // pickAll (if no children, nothing to pick)
  3459.     XtSetValues(menuItems[SV_EDIT_PICK_ALL].widget, args, 1);
  3460. #endif
  3461.  
  3462.  
  3463.     // enable/disable based on the number of selected objects
  3464.     if (selection->getNumSelected() == 0)
  3465.      XtSetArg(args[0], XmNsensitive, False);
  3466.     else XtSetArg(args[0], XmNsensitive, True);
  3467.     
  3468.     // if nothing selected, then cannot pick parent, cut, copy, delete,
  3469.     // view selection, bring up editors
  3470. #ifndef EXPLORER
  3471.     XtSetValues(menuItems[SV_EDIT_PICK_PARENT].widget, args, 1);
  3472.     XtSetValues(menuItems[SV_EDIT_CUT].widget, args, 1);
  3473.     XtSetValues(menuItems[SV_EDIT_COPY].widget, args, 1);
  3474.     XtSetValues(menuItems[SV_EDIT_DELETE].widget, args, 1);
  3475. #endif
  3476.     XtSetValues(menuItems[SV_VIEW_SELECTION].widget, args, 1);
  3477.     XtSetValues(menuItems[SV_EDITOR_TRANSFORM].widget, args, 1);
  3478.     XtSetValues(menuItems[SV_EDITOR_MATERIAL].widget, args, 1);
  3479.     XtSetValues(menuItems[SV_EDITOR_COLOR].widget, args, 1);
  3480. }
  3481.  
  3482. ////////////////////////////////////////////////////////////////////////
  3483. //
  3484. //  Called by Xt when a menu is about to be displayed.
  3485. //  This gives us a chance to update any items in the menu.
  3486. //
  3487. //  Use: static private
  3488. //
  3489. void
  3490. SoSceneViewer::menuDisplay(Widget, SoSceneViewerData *data, XtPointer)
  3491. //
  3492. ////////////////////////////////////////////////////////////////////////
  3493. {
  3494.     SoSceneViewer *sv = data->classPt;
  3495.     Arg args[1];
  3496.     char str[100];
  3497.     XmString xmstr;
  3498.     
  3499.     switch (data->id) {
  3500.     case SV_FILE:
  3501.         // disable saving if there isn't any geometry
  3502.         if (sv->selection->getNumChildren() == 0)
  3503.             XtSetArg(args[0], XmNsensitive, False);
  3504.         else 
  3505.             XtSetArg(args[0], XmNsensitive, True);
  3506.         
  3507.         XtSetValues(sv->menuItems[SV_FILE_SAVE].widget, args, 1);
  3508.         XtSetValues(sv->menuItems[SV_FILE_SAVE_AS].widget, args, 1);
  3509.         
  3510.         // update the "Save" menu entry to reflect the current file name
  3511.         strcpy(str, "Save");
  3512.         if (sv->fileName != NULL) {
  3513.         // get the file name withought the entire path
  3514.         char *pt = strrchr(sv->fileName, '/');   // last occurance of '/'
  3515.         pt = (pt == NULL) ? sv->fileName : pt + 1;
  3516.         strcat(str, " -> ");
  3517.         strcat(str, pt);
  3518.         }
  3519.         xmstr = XmStringCreate(str, XmSTRING_DEFAULT_CHARSET);
  3520.         XtSetArg(args[0], XmNlabelString, xmstr);
  3521.         XtSetValues(sv->menuItems[SV_FILE_SAVE].widget, args, 1);
  3522.         //??? can we ever free the xmstr?
  3523.         break;
  3524.         
  3525. #ifndef EXPLORER
  3526.         case SV_EDIT:
  3527.         // disable cut, copy, delete, pickParent if there is no selection
  3528.         if(sv->selection->getNumSelected() == 0)
  3529.             XtSetArg(args[0], XmNsensitive, False);
  3530.         else 
  3531.             XtSetArg(args[0], XmNsensitive, True);
  3532.         
  3533.         XtSetValues(sv->menuItems[SV_EDIT_PICK_PARENT].widget, args, 1);
  3534.         XtSetValues(sv->menuItems[SV_EDIT_CUT].widget, args, 1);
  3535.         XtSetValues(sv->menuItems[SV_EDIT_COPY].widget, args, 1);
  3536.         XtSetValues(sv->menuItems[SV_EDIT_DELETE].widget, args, 1);
  3537.         
  3538.         // disable pick all if there are nothing to pick
  3539.         if (sv->selection->getNumChildren() == 0)
  3540.             XtSetArg(args[0], XmNsensitive, False);
  3541.         else 
  3542.             XtSetArg(args[0], XmNsensitive, True);
  3543.         XtSetValues(sv->menuItems[SV_EDIT_PICK_ALL].widget, args, 1);
  3544.         break;
  3545. #endif /* EXPLORER */
  3546.         
  3547.     case SV_VIEW:
  3548.         // set pick/edit toggle
  3549.         if ( sv->isViewing() )
  3550.          TOGGLE_OFF(sv->menuItems[SV_VIEW_PICK].widget);
  3551.         else TOGGLE_ON(sv->menuItems[SV_VIEW_PICK].widget);
  3552.         
  3553. #ifdef EXPLORER
  3554.         // set user pick toggle
  3555.         if ( sv->userModeFlag )
  3556.          TOGGLE_ON(sv->menuItems[SV_VIEW_USER].widget);
  3557.         else TOGGLE_OFF(sv->menuItems[SV_VIEW_USER].widget);
  3558. #endif
  3559.         // Set the correct viewer
  3560.         TOGGLE_OFF(sv->menuItems[SV_VIEW_EXAMINER].widget);
  3561.         TOGGLE_OFF(sv->menuItems[SV_VIEW_WALK].widget);
  3562.         TOGGLE_OFF(sv->menuItems[SV_VIEW_PLANE].widget);
  3563.         TOGGLE_OFF(sv->menuItems[SV_VIEW_FLY].widget);
  3564.         switch ( sv->whichViewer ) {
  3565.         case SV_VWR_EXAMINER:
  3566.             TOGGLE_ON(sv->menuItems[SV_VIEW_EXAMINER].widget);
  3567.             break;
  3568.         case SV_VWR_WALK:
  3569.             TOGGLE_ON(sv->menuItems[SV_VIEW_WALK].widget);
  3570.             break;
  3571.         case SV_VWR_FLY:
  3572.             TOGGLE_ON(sv->menuItems[SV_VIEW_FLY].widget);
  3573.             break;
  3574.         case SV_VWR_PLANE:
  3575.             TOGGLE_ON(sv->menuItems[SV_VIEW_PLANE].widget);
  3576.             break;
  3577.         }
  3578.         
  3579.         // set the correct transparency type
  3580.         TOGGLE_OFF(sv->menuItems[SV_VIEW_SCREEN_TRANSPARENCY].widget);
  3581.         TOGGLE_OFF(sv->menuItems[SV_VIEW_BLEND_TRANSPARENCY].widget);
  3582.         TOGGLE_OFF(sv->menuItems[SV_VIEW_DELAY_BLEND_TRANSPARENCY].widget);
  3583.         TOGGLE_OFF(sv->menuItems[SV_VIEW_SORT_BLEND_TRANSPARENCY].widget);
  3584.         switch( sv->getTransparencyType() ) {
  3585.         case SoGLRenderAction::SCREEN_DOOR:
  3586.             TOGGLE_ON(sv->menuItems[SV_VIEW_SCREEN_TRANSPARENCY].widget);
  3587.             break;
  3588.         case SoGLRenderAction::BLEND:
  3589.             TOGGLE_ON(sv->menuItems[SV_VIEW_BLEND_TRANSPARENCY].widget);
  3590.             break;
  3591.         case SoGLRenderAction::DELAYED_BLEND:
  3592.             TOGGLE_ON(sv->menuItems[SV_VIEW_DELAY_BLEND_TRANSPARENCY].widget);
  3593.             break;
  3594.         case SoGLRenderAction::SORTED_OBJECT_BLEND:
  3595.             TOGGLE_ON(sv->menuItems[SV_VIEW_SORT_BLEND_TRANSPARENCY].widget);
  3596.             break;
  3597.         }
  3598.         
  3599.         // disable view selection if nothing is selected
  3600.         if ( sv->selection->getNumSelected() == 0 )
  3601.             XtSetArg(args[0], XmNsensitive, False);
  3602.         else 
  3603.             XtSetArg(args[0], XmNsensitive, True);
  3604.         XtSetValues(sv->menuItems[SV_VIEW_SELECTION].widget, args, 1);
  3605.         
  3606.         // set fog toggle
  3607.         if ( sv->fogFlag )
  3608.          TOGGLE_ON(sv->menuItems[SV_VIEW_FOG].widget);
  3609.         else TOGGLE_OFF(sv->menuItems[SV_VIEW_FOG].widget);
  3610.         
  3611.         // set antialiasing toggle
  3612.         if ( sv->antialiasingFlag )
  3613.          TOGGLE_ON(sv->menuItems[SV_VIEW_ANTIALIASING].widget);
  3614.         else TOGGLE_OFF(sv->menuItems[SV_VIEW_ANTIALIASING].widget);
  3615.         
  3616.         break;
  3617.         
  3618. #ifndef EXPLORER
  3619.         case SV_SELECTION:
  3620.         // mirror the selection policy
  3621.         TOGGLE_OFF(sv->menuItems[SV_SEL_SINGLE_SELECT].widget);
  3622.         TOGGLE_OFF(sv->menuItems[SV_SEL_TOGGLE_SELECT].widget);
  3623.         TOGGLE_OFF(sv->menuItems[SV_SEL_SHIFT_SELECT].widget);
  3624.         switch ( sv->selection->getSelectionPolicy() ) {
  3625.         case SoSelection::SINGLE:
  3626.             TOGGLE_ON (sv->menuItems[SV_SEL_SINGLE_SELECT].widget);
  3627.             break;
  3628.             case SoSelection::TOGGLE:
  3629.             TOGGLE_ON (sv->menuItems[SV_SEL_TOGGLE_SELECT].widget);
  3630.             break;
  3631.             case SoSelection::SHIFT:
  3632.             TOGGLE_ON (sv->menuItems[SV_SEL_SHIFT_SELECT].widget);
  3633.             break;
  3634.             case SoSelection::CUSTOM:
  3635.         default:
  3636.             fprintf(stderr, "INTERNAL ERROR, unknown selection policy\n");
  3637.             break;
  3638.         }
  3639.         
  3640.         // and the highlight style
  3641.         TOGGLE_OFF(sv->menuItems[SV_SEL_LINE_HIGHLIGHT].widget);
  3642.         TOGGLE_OFF(sv->menuItems[SV_SEL_BBOX_HIGHLIGHT].widget);
  3643.         TOGGLE_OFF(sv->menuItems[SV_SEL_NO_HIGHLIGHT].widget);
  3644.         if (sv->selection->getHighlightStyle() == sv->lineHighlight)
  3645.         TOGGLE_ON (sv->menuItems[SV_SEL_LINE_HIGHLIGHT].widget);
  3646.         else if (sv->selection->getHighlightStyle() == sv->boxHighlight)
  3647.         TOGGLE_ON (sv->menuItems[SV_SEL_BBOX_HIGHLIGHT].widget);
  3648.         else     // (sv->selection->getHighlightStyle() == NULL)
  3649.         TOGGLE_ON(sv->menuItems[SV_SEL_NO_HIGHLIGHT].widget);
  3650.         break;
  3651. #endif /* EXPLORER */
  3652.         
  3653.         case SV_EDITOR:
  3654.         // disable items if there is no selection
  3655.         if(sv->selection->getNumSelected() == 0)
  3656.             XtSetArg(args[0], XmNsensitive, False);
  3657.         else 
  3658.             XtSetArg(args[0], XmNsensitive, True);
  3659.         
  3660.         XtSetValues(sv->menuItems[SV_EDITOR_TRANSFORM].widget, args, 1);
  3661.         XtSetValues(sv->menuItems[SV_EDITOR_MATERIAL].widget, args, 1);
  3662.         XtSetValues(sv->menuItems[SV_EDITOR_COLOR].widget, args, 1);
  3663.         break;
  3664.         
  3665.        case SV_MANIP:
  3666.  
  3667.         // First, the section with the different types of manipulators.
  3668.         TOGGLE_OFF( sv->menuItems[SV_MANIP_HANDLEBOX].widget );
  3669.         TOGGLE_OFF( sv->menuItems[SV_MANIP_TRACKBALL].widget );
  3670.         TOGGLE_OFF( sv->menuItems[SV_MANIP_JACK].widget );
  3671.         TOGGLE_OFF( sv->menuItems[SV_MANIP_XFBOX].widget );
  3672.         TOGGLE_OFF( sv->menuItems[SV_MANIP_DRAGPOINT].widget );
  3673.         TOGGLE_OFF( sv->menuItems[SV_MANIP_NONE].widget );
  3674.         
  3675.         // Turn appropriate radio button on
  3676.         if (sv->curManip == SV_HANDLEBOX)
  3677.         TOGGLE_ON(sv->menuItems[SV_MANIP_HANDLEBOX].widget);
  3678.         else if (sv->curManip == SV_TRACKBALL)
  3679.         TOGGLE_ON(sv->menuItems[SV_MANIP_TRACKBALL].widget);
  3680.         else if (sv->curManip == SV_JACK)
  3681.         TOGGLE_ON(sv->menuItems[SV_MANIP_JACK].widget);
  3682.         else if (sv->curManip == SV_XFBOX)
  3683.         TOGGLE_ON(sv->menuItems[SV_MANIP_XFBOX].widget);
  3684.         else if (sv->curManip == SV_DRAGPOINT)
  3685.         TOGGLE_ON(sv->menuItems[SV_MANIP_DRAGPOINT].widget);
  3686.         else 
  3687.         TOGGLE_ON(sv->menuItems[SV_MANIP_NONE].widget);
  3688.  
  3689.         // Next, the toggle that says whether we replace current 
  3690.         // manipulators every time we change the type given in the menu.
  3691.         if (sv->curManipReplaces == TRUE ) 
  3692.         TOGGLE_ON(  sv->menuItems[SV_MANIP_REPLACE_ALL].widget );
  3693.         else
  3694.         TOGGLE_OFF( sv->menuItems[SV_MANIP_REPLACE_ALL].widget );
  3695.  
  3696.         break;
  3697.         
  3698.     case SV_LIGHT:
  3699.         // disable the add light entries if we have more than 8 lights
  3700.         if (sv->lightDataList.length() < 8)
  3701.             XtSetArg(args[0], XmNsensitive, True);
  3702.         else 
  3703.             XtSetArg(args[0], XmNsensitive, False);
  3704.         
  3705.         XtSetValues(sv->menuItems[SV_LIGHT_ADD_DIRECT].widget, args, 1);
  3706.         XtSetValues(sv->menuItems[SV_LIGHT_ADD_POINT].widget, args, 1);
  3707.         XtSetValues(sv->menuItems[SV_LIGHT_ADD_SPOT].widget, args, 1);
  3708.         
  3709.         // update the headlight label (show on/off with '*')
  3710.         sv->isHeadlight() ? strcpy(str, "* ") : strcpy(str, "  ");
  3711.         strcat(str, sv->headlightData->name);
  3712.         xmstr = XmStringCreate(str, XmSTRING_DEFAULT_CHARSET);
  3713.         XtSetArg(args[0], XmNlabelString, xmstr);
  3714.         XtSetValues(sv->headlightData->cascadeWidget, args, 1);
  3715.         //??? can we ever free the xmstr?
  3716.         
  3717.         // update the lights label (show on/off with '*')
  3718.         {
  3719.         for (int i=0; i < sv->lightDataList.length(); i++) {
  3720.             SvLightData *data = (SvLightData *) sv->lightDataList[i];
  3721.             IS_LIGHT_ON(data->lightSwitch) ? strcpy(str, "* ") : strcpy(str, "  ");
  3722.             strcat(str, data->name);
  3723.             xmstr = XmStringCreate(str, XmSTRING_DEFAULT_CHARSET);
  3724.             XtSetArg(args[0], XmNlabelString, xmstr);
  3725.             XtSetValues(data->cascadeWidget, args, 1);
  3726.             //??? can we ever free the xmstr?
  3727.         }
  3728.         }
  3729.         break;
  3730.         
  3731.     default:
  3732.         break;
  3733.     }
  3734. }
  3735.  
  3736. ////////////////////////////////////////////////////////////////////////
  3737. //
  3738. // Description:
  3739. //    Determines whether a given node is affected by a transform.
  3740. //
  3741. // Use: static, public
  3742. //
  3743. SbBool
  3744. SoSceneViewer::isAffectedByTransform(
  3745.     SoNode *theNode )        // node to be affected?
  3746. //
  3747. ////////////////////////////////////////////////////////////////////////
  3748. {
  3749.     if ( theNode->isOfType( SoGroup::getClassTypeId() )
  3750.         || theNode->isOfType( SoShape::getClassTypeId() )
  3751.         || theNode->isOfType( SoCamera::getClassTypeId() )
  3752.         || theNode->isOfType( SoLight::getClassTypeId() ) )  {
  3753.     return TRUE;
  3754.     }
  3755.     return FALSE;
  3756. }
  3757.  
  3758. ////////////////////////////////////////////////////////////////////////
  3759. //
  3760. // Description:
  3761. //    Determines whether a given node is affected by material node.
  3762. //
  3763. // Use: static, public
  3764. //
  3765. SbBool
  3766. SoSceneViewer::isAffectedByMaterial(
  3767.     SoNode *theNode )        // node to be affected?
  3768. //
  3769. ////////////////////////////////////////////////////////////////////////
  3770. {
  3771.     if ( theNode->isOfType( SoGroup::getClassTypeId() )
  3772.         || theNode->isOfType( SoShape::getClassTypeId() ) ) {
  3773.     return TRUE;
  3774.     }
  3775.     return FALSE;
  3776. }
  3777.  
  3778. ////////////////////////////////////////////////////////////////////////
  3779. //
  3780. // Description:
  3781. //    Create the lights and camera environment structure.
  3782. //
  3783. // Use: private
  3784. //
  3785. void
  3786. SoSceneViewer::createLightsCameraEnvironment()
  3787. //
  3788. ////////////////////////////////////////////////////////////////////////
  3789. {
  3790.     // Group {
  3791.     //      Label { "SoSceneViewer Environment v3.0" }
  3792.     //    Camera {}
  3793.     //    Environment {}
  3794.     //    Group {
  3795.     //        Switch { Light 1 }        # switch is child 0, light is child 0
  3796.     //        Switch { Light 2 }        # switch is child 1, light is child 0
  3797.     //        ...
  3798.     //    }
  3799.     // }
  3800.     
  3801.     lightsCameraEnvironment = new SoGroup;
  3802.     camera                  = new SoPerspectiveCamera;
  3803.     environment             = new SoEnvironment;
  3804.     lightGroup                 = new SoGroup;
  3805.     envLabel              = new SoLabel;
  3806.  
  3807.     envLabel->label.setValue(SV_ENV_LABEL);
  3808.     lightsCameraEnvironment->addChild(envLabel);
  3809.     lightsCameraEnvironment->addChild(camera);
  3810.     lightsCameraEnvironment->addChild(environment);
  3811.     lightsCameraEnvironment->addChild(lightGroup);
  3812. }
  3813.  
  3814. ////////////////////////////////////////////////////////////////////////
  3815. //
  3816. // Description:
  3817. //    Brings up the "About..." dialog (same code as gavin demo programs)
  3818. //
  3819. // Use: private
  3820. //
  3821. void
  3822. SoSceneViewer::showAboutDialog()
  3823. //
  3824. ////////////////////////////////////////////////////////////////////////
  3825. {
  3826.     if (access("/usr/share/help/SceneViewer/SceneViewer.about", R_OK) != 0)
  3827.     {
  3828.     system("xconfirm -t 'Sorry, could not find "
  3829.            "/usr/share/help/SceneViewer/SceneViewer.about' > /dev/null");
  3830.     return;
  3831.     }
  3832.  
  3833.     char command[100];
  3834.     sprintf(command, "showcase -v /usr/share/help/SceneViewer/SceneViewer.about");
  3835.  
  3836.     int err = system(command);
  3837.     if (err)
  3838.     {
  3839.     system("xconfirm -t 'You must install showcase"
  3840.            " for this function to work' > /dev/null");
  3841.     return;
  3842.     }
  3843. }
  3844.  
  3845. #ifdef EXPLORER
  3846. void SoSceneViewer::changeCamera(SoCamera *newCamera)
  3847. {
  3848.         lightsCameraEnvironment->insertChild(newCamera,0);
  3849.         setCamera(newCamera);
  3850.         lightsCameraEnvironment->removeChild(camera);
  3851.         camera = newCamera;
  3852. }
  3853. #endif
  3854.  
  3855. //
  3856. // define those generic virtual functions
  3857. //
  3858. const char *
  3859. SoSceneViewer::getDefaultWidgetName() const
  3860. { return "SoSceneViewer"; }
  3861.  
  3862. const char *
  3863. SoSceneViewer::getDefaultTitle() const
  3864. { return "SceneViewer"; }
  3865.  
  3866. const char *
  3867. SoSceneViewer::getDefaultIconTitle() const
  3868. { return "SceneViewer"; }
  3869. //
  3870. // added by smf
  3871.  
  3872. ////////////////////////////////////////////////////////////////////////
  3873. //
  3874. // Description:
  3875. //     Broadcast the Enviroment nodes (camera and lights) 
  3876. //
  3877. // Use: private
  3878. SbBool
  3879. SoSceneViewer::BroadcastEnv()
  3880. //
  3881. ////////////////////////////////////////////////////////////////////////
  3882. {
  3883.  
  3884.     SoWriteAction    nwa;
  3885.     int cnt;
  3886.     nwa.getOutput()->setBuffer(mybuff,1000,NULL);
  3887.     nwa.apply(envLabel);
  3888.     nwa.apply(camera);
  3889.     nwa.apply(environment);
  3890.     nwa.apply(lightGroup);
  3891.     if (isHeadlight())
  3892.         nwa.apply(getHeadlight());
  3893.  
  3894.     cnt = sendto(outfd, mybuff, strlen(mybuff), 0, &outaddr, outaddrlen);
  3895. #ifdef MYDEBUG
  3896.     printf("sent %d bytes to network\n",cnt);
  3897. #endif
  3898.         if (cnt < 0) {
  3899.             perror("sendto");
  3900.         }
  3901.  
  3902. #ifdef MYDEBUG
  3903.     printf("BUFFER = %s\n",mybuff);
  3904. #endif
  3905.     return TRUE;
  3906. }
  3907.  
  3908. ////////////////////////////////////////////////////////////////////////
  3909. //
  3910. // Description:
  3911. //    Read environment data from network. We expect the following nodes:
  3912. //
  3913. //  Group {
  3914. //    Label { "SoSceneViewer Environment v3.0" }
  3915. //    Camera {}
  3916. //    Environment {}
  3917. //    LightGroup {
  3918. //      Switch { DirectionalLight }  # 1
  3919. //      ...
  3920. //      Switch { DirectionalLight }  # 6
  3921. //    }
  3922. //    DirectionalLight {}       # optional headlight
  3923. //  }
  3924. //
  3925. // Use: private
  3926. SbBool
  3927. SoSceneViewer::ReadBroadcastEnv()
  3928. //
  3929. ////////////////////////////////////////////////////////////////////////
  3930. {
  3931.     SoInput in;
  3932.     SoNode *n;
  3933.     SoGroup *g = NULL;
  3934.     SoLabel *l = NULL;
  3935.     SbBool isValid = FALSE;
  3936.     SbBool ok = FALSE;
  3937.  
  3938. while(!ok) 
  3939.    {
  3940. //    if (! in.setBuffer(mybuff,strlen(mybuff))) {
  3941.     //// display an error dialog
  3942.     //char str[100];
  3943.     //strcpy(str, "Error Reading Broadcast: ");
  3944.     //SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  3945.     //return FALSE;
  3946.     //}
  3947.     in.setBuffer(mybuff,strlen(mybuff)); 
  3948.     
  3949.     
  3950.     if ((ok = SoDB::read(&in, n)) && n != NULL) {
  3951.     // we expect a label first
  3952.     n->ref();
  3953.     if (n->isOfType(SoLabel::getClassTypeId())) {
  3954.         l = (SoLabel *) n;
  3955.         isValid = (strcmp(l->label.getValue().getString(),
  3956.                   SV_ENV_LABEL) == 0);
  3957.     }
  3958.     n->unref();
  3959.     }
  3960.   }
  3961. //    else if (!ok) {
  3962.      //display error dialog if there were reading errors
  3963. //    char str[100];
  3964. //    strcpy(str, "Error reading file: ");
  3965. //    strcat(str, filename);
  3966. //    SoXt::createSimpleErrorDialog(mgrWidget, "File Error Dialog", str);
  3967. //    return FALSE;
  3968. //   }
  3969.  
  3970.     // if ok, read the rest.
  3971.     if (isValid) {
  3972.     // Camera
  3973.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  3974.         n->ref();
  3975.         if (n->isOfType(SoPerspectiveCamera::getClassTypeId())) {
  3976.         // viewers need to be detached from the old camera
  3977.         // and attached to the new. both cameras must be in
  3978.         // the scene graph for this to happen smoothly.
  3979.         SoPerspectiveCamera *newCamera = (SoPerspectiveCamera *) n;
  3980.         lightsCameraEnvironment->insertChild(newCamera, 0);
  3981.         setCamera(newCamera);
  3982.         lightsCameraEnvironment->removeChild(camera);
  3983.         camera = newCamera;            
  3984.         }
  3985.         n->unref();
  3986.     }
  3987.     // Environment
  3988.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  3989.         n->ref();
  3990.         if (n->isOfType(SoEnvironment::getClassTypeId())) {
  3991.         lightsCameraEnvironment->replaceChild(environment, n);
  3992.         environment = (SoEnvironment *) n;
  3993.         }
  3994.         n->unref();
  3995.     }
  3996.     // Light group
  3997.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  3998.         n->ref();
  3999.         if (n->isOfType(SoGroup::getClassTypeId())) {
  4000.         
  4001.         // remove all of the existing lights
  4002.         for (int i = lightDataList.length(); i > 0; i--)
  4003.             removeLight( (SvLightData *) lightDataList[i-1] );
  4004.         
  4005.         lightsCameraEnvironment->replaceChild(lightGroup, n);
  4006.         lightGroup = (SoGroup *) n;
  4007.         
  4008.         // now create a light entry for each new light
  4009.         for (i=0; i < lightGroup->getNumChildren(); i++) {
  4010.             SoNode *node = lightGroup->getChild(i);
  4011.             if (node->isOfType(SoSwitch::getClassTypeId())) {
  4012.             SoSwitch *sw = (SoSwitch *) node;
  4013.             node = sw->getChild(0);
  4014.             if (node->isOfType(SoLight::getClassTypeId()))
  4015.                 addLightEntry((SoLight *)node, sw);
  4016.             }
  4017.         }
  4018.         }
  4019.         n->unref();
  4020.     }
  4021.     // Headlight (optional) - if not there, turn headlight off
  4022.     if (SoDB::read(&in, n) != FALSE && (n != NULL)) {
  4023.         n->ref();
  4024.         if (n->isOfType(SoDirectionalLight::getClassTypeId())) {
  4025.         SoDirectionalLight *headlight = getHeadlight();
  4026.         SoDirectionalLight *newLight = (SoDirectionalLight *) n;
  4027.         headlight->intensity.setValue(newLight->intensity.getValue());
  4028.         headlight->color.setValue(newLight->color.getValue());
  4029.         headlight->direction.setValue(newLight->direction.getValue());
  4030.         setHeadlight(TRUE);
  4031.         }
  4032.         n->unref();
  4033.     }
  4034.     else setHeadlight(FALSE);
  4035.     }
  4036.     else {
  4037.     fprintf(stderr, "Sorry, file is not formatted correctly\n");
  4038.     }
  4039.     
  4040.     return TRUE;
  4041. }
  4042.  
  4043. int readnet()
  4044. {
  4045.     int cnt=1;
  4046.     int flag = 0 ;
  4047.  
  4048.     while(cnt > 0)
  4049.      {
  4050.       cnt = recvfrom(infd, temp, sizeof(temp), 0, &inaddr, &inaddrlen);
  4051.       if(cnt > 0) 
  4052.         {
  4053.           bcopy(temp,mybuff,1000);
  4054.           flag=1;
  4055.         }
  4056.      }
  4057.         if (! flag) {
  4058.             return(0);
  4059.        }
  4060.       if(!strncmp(mybuff,"#Inventor V1.0 ascii",20))return(ENVIRONMENT);
  4061. }
  4062.  
  4063. // added by smf
  4064. // called by start camera callback
  4065. void mystartcallback(void *tmp,SoXtViewer *)
  4066. {
  4067. #ifdef MYDEBUG 
  4068.   printf("START Camera, rotflag=1\n");
  4069. #endif
  4070. rotflag=1;
  4071. }
  4072.  
  4073. // called by finish camera callback
  4074. void mystopcallback(void *tmp,SoXtViewer *sv)
  4075. {
  4076. #ifdef MYDEBUG 
  4077.   printf("STOP camera,WRITE,rotflag=0\n");
  4078. #endif
  4079.   ((SoSceneViewer *)mysv)->BroadcastEnv();
  4080.    rotflag=0;
  4081. }
  4082.  
  4083. // called by timer callback
  4084. void myreadcallback(void *tmp,SoSensor *sv)
  4085. {
  4086. #ifdef MYDEBUG 
  4087.     printf("FLAG=1,DETACH ENVIRO, READ, ATTACH ENVIRO\n");
  4088. #endif
  4089.  
  4090.   switch (readnet())
  4091.     {
  4092.      case ENVIRONMENT:
  4093.        flag=1;
  4094.        if(envirosensor->getNumAttachments()) envirosensor->detach(mysv->lightsCameraEnvironment);
  4095.         if(! rotflag ){
  4096.                 ((SoSceneViewer *)mysv)->ReadBroadcastEnv();
  4097.         }
  4098.         envirosensor->attach(mysv->lightsCameraEnvironment);
  4099.        break;
  4100.      
  4101.      default:
  4102.        break;
  4103.     }
  4104. }
  4105.  
  4106. // called by datasensor callback
  4107. void mywritecallback(void *tmp,SoSensor *sv)
  4108. {
  4109. if(flag)
  4110. {
  4111. #ifdef MYDEBUG 
  4112.  printf("FLAG=0\n");
  4113. #endif
  4114. flag=0;
  4115. }
  4116. else
  4117.  {
  4118. #ifdef MYDEBUG 
  4119.   printf("TIMER OFF, DETACH ENVIRO, WRITE, ATTACH ENVIRO, TIMER %d\n",timerflag);
  4120. #endif
  4121.    timersensor->unschedule();
  4122.    if(envirosensor->getNumAttachments()) envirosensor->detach(mysv->lightsCameraEnvironment);
  4123.    ((SoSceneViewer *)mysv)->BroadcastEnv();
  4124.    envirosensor->attach(mysv->lightsCameraEnvironment);
  4125.    if(timerflag)timersensor->schedule(SbTime((unsigned long)DATATIME));
  4126.  }
  4127.  
  4128. }
  4129.  
  4130.  
  4131.